Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-2026 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU 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 General Public License for more details.
12 :
13 : You should have received a copy of the GNU General Public License along with
14 : TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
15 : */
16 : /**
17 : * @file util/secmod_cs.c
18 : * @brief Standalone process to perform private key CS operations
19 : * @author Christian Grothoff
20 : *
21 : * Key design points:
22 : * - EVERY thread of the exchange will have its own pair of connections to the
23 : * crypto helpers. This way, every thread will also have its own /keys state
24 : * and avoid the need to synchronize on those.
25 : * - auditor signatures and master signatures are to be kept in the exchange DB,
26 : * and merged with the public keys of the helper by the exchange HTTPD!
27 : * - the main loop of the helper is SINGLE-THREADED, but there are
28 : * threads for crypto-workers which do the signing in parallel, one per client.
29 : * - thread-safety: signing happens in parallel, thus when REMOVING private keys,
30 : * we must ensure that all signers are done before we fully free() the
31 : * private key. This is done by reference counting (as work is always
32 : * assigned and collected by the main thread).
33 : */
34 : #include "platform.h"
35 : #include "taler/taler_util.h"
36 : #include "secmod_cs.h"
37 : #include <gcrypt.h>
38 : #include <pthread.h>
39 : #include <sys/eventfd.h>
40 : #include "taler/taler_error_codes.h"
41 : #include "taler/taler_signatures.h"
42 : #include "secmod_common.h"
43 : #include <poll.h>
44 :
45 :
46 : /**
47 : * Information we keep per denomination.
48 : */
49 : struct Denomination;
50 :
51 :
52 : /**
53 : * One particular denomination key.
54 : */
55 : struct DenominationKey
56 : {
57 :
58 : /**
59 : * Kept in a DLL of the respective denomination. Sorted by anchor time.
60 : */
61 : struct DenominationKey *next;
62 :
63 : /**
64 : * Kept in a DLL of the respective denomination. Sorted by anchor time.
65 : */
66 : struct DenominationKey *prev;
67 :
68 : /**
69 : * Denomination this key belongs to.
70 : */
71 : struct Denomination *denom;
72 :
73 : /**
74 : * Name of the file this key is stored under.
75 : */
76 : char *filename;
77 :
78 : /**
79 : * The private key of the denomination.
80 : */
81 : struct GNUNET_CRYPTO_CsPrivateKey denom_priv;
82 :
83 : /**
84 : * The public key of the denomination.
85 : */
86 : struct GNUNET_CRYPTO_CsPublicKey denom_pub;
87 :
88 : /**
89 : * Message to transmit to clients to introduce this public key.
90 : */
91 : struct TALER_CRYPTO_CsKeyAvailableNotification *an;
92 :
93 : /**
94 : * Hash of this denomination's public key.
95 : */
96 : struct TALER_CsPubHashP h_cs;
97 :
98 : /**
99 : * Time at which this key is supposed to become valid.
100 : */
101 : struct GNUNET_TIME_Timestamp anchor_start;
102 :
103 : /**
104 : * Time at which this key is supposed to expire (exclusive).
105 : */
106 : struct GNUNET_TIME_Timestamp anchor_end;
107 :
108 : /**
109 : * Generation when this key was created or revoked.
110 : */
111 : uint64_t key_gen;
112 :
113 : /**
114 : * Reference counter. Counts the number of threads that are
115 : * using this key at this time.
116 : */
117 : unsigned int rc;
118 :
119 : /**
120 : * Flag set to true if this key has been purged and the memory
121 : * must be freed as soon as @e rc hits zero.
122 : */
123 : bool purge;
124 :
125 : };
126 :
127 :
128 : struct Denomination
129 : {
130 :
131 : /**
132 : * Kept in a DLL. Sorted by #denomination_action_time().
133 : */
134 : struct Denomination *next;
135 :
136 : /**
137 : * Kept in a DLL. Sorted by #denomination_action_time().
138 : */
139 : struct Denomination *prev;
140 :
141 : /**
142 : * Head of DLL of actual keys of this denomination.
143 : */
144 : struct DenominationKey *keys_head;
145 :
146 : /**
147 : * Tail of DLL of actual keys of this denomination.
148 : */
149 : struct DenominationKey *keys_tail;
150 :
151 : /**
152 : * How long can coins be withdrawn (generated)? Should be small
153 : * enough to limit how many coins will be signed into existence with
154 : * the same key, but large enough to still provide a reasonable
155 : * anonymity set.
156 : */
157 : struct GNUNET_TIME_Relative duration_withdraw;
158 :
159 : /**
160 : * Calendar interval the start of the validity period of our keys is
161 : * rounded down to (and the end of the validity period rounded up to).
162 : * #GNUNET_TIME_RI_NONE (the default) disables the rounding. Donau sets
163 : * this to #GNUNET_TIME_RI_YEAR so that its keys are valid for exactly one
164 : * calendar year (starting January 1st UTC), even if the key was generated
165 : * in the middle of the year.
166 : */
167 : enum GNUNET_TIME_RounderInterval anchor_round;
168 :
169 : /**
170 : * What is the configuration section of this denomination type? Also used
171 : * for the directory name where the denomination keys are stored.
172 : */
173 : char *section;
174 :
175 : };
176 :
177 :
178 : /**
179 : * A semaphore.
180 : */
181 : struct Semaphore
182 : {
183 : /**
184 : * Mutex for the semaphore.
185 : */
186 : pthread_mutex_t mutex;
187 :
188 : /**
189 : * Condition variable for the semaphore.
190 : */
191 : pthread_cond_t cv;
192 :
193 : /**
194 : * Counter of the semaphore.
195 : */
196 : unsigned int ctr;
197 : };
198 :
199 :
200 : /**
201 : * Job in a batch sign request.
202 : */
203 : struct BatchJob;
204 :
205 : /**
206 : * Handle for a thread that does work in batch signing.
207 : */
208 : struct Worker
209 : {
210 : /**
211 : * Kept in a DLL.
212 : */
213 : struct Worker *prev;
214 :
215 : /**
216 : * Kept in a DLL.
217 : */
218 : struct Worker *next;
219 :
220 : /**
221 : * Job this worker should do next.
222 : */
223 : struct BatchJob *job;
224 :
225 : /**
226 : * Semaphore to signal the worker that a job is available.
227 : */
228 : struct Semaphore sem;
229 :
230 : /**
231 : * Handle for this thread.
232 : */
233 : pthread_t pt;
234 :
235 : /**
236 : * Set to true if the worker should terminate.
237 : */
238 : bool do_shutdown;
239 : };
240 :
241 :
242 : /**
243 : * Job in a batch sign request.
244 : */
245 : struct BatchJob
246 : {
247 :
248 : /**
249 : * Thread doing the work.
250 : */
251 : struct Worker *worker;
252 :
253 : /**
254 : * Semaphore to signal that the job is finished.
255 : */
256 : struct Semaphore sem;
257 :
258 : /**
259 : * Computation status.
260 : */
261 : enum TALER_ErrorCode ec;
262 :
263 : /**
264 : * Which type of request is this?
265 : */
266 : enum { TYPE_SIGN, TYPE_RDERIVE } type;
267 :
268 : /**
269 : * Details depending on @e type.
270 : */
271 : union
272 : {
273 :
274 : /**
275 : * Details if @e type is TYPE_SIGN.
276 : */
277 : struct
278 : {
279 : /**
280 : * Request we are working on.
281 : */
282 : const struct TALER_CRYPTO_CsSignRequestMessage *sr;
283 :
284 : /**
285 : * Result with the signature.
286 : */
287 : struct GNUNET_CRYPTO_CsBlindSignature cs_answer;
288 : } sign;
289 :
290 : /**
291 : * Details if type is TYPE_RDERIVE.
292 : */
293 : struct
294 : {
295 : /**
296 : * Request we are answering.
297 : */
298 : const struct TALER_CRYPTO_CsRDeriveRequest *rdr;
299 :
300 : /**
301 : * Pair of points to return.
302 : */
303 : struct GNUNET_CRYPTO_CSPublicRPairP rpairp;
304 :
305 : } rderive;
306 :
307 : } details;
308 :
309 : };
310 :
311 : /**
312 : * Head of DLL of workers ready for more work.
313 : */
314 : static struct Worker *worker_head;
315 :
316 : /**
317 : * Tail of DLL of workers ready for more work.
318 : */
319 : static struct Worker *worker_tail;
320 :
321 : /**
322 : * Lock for manipulating the worker DLL.
323 : */
324 : static pthread_mutex_t worker_lock = PTHREAD_MUTEX_INITIALIZER;
325 :
326 : /**
327 : * Total number of workers that were started.
328 : */
329 : static unsigned int workers;
330 :
331 : /**
332 : * Semaphore used to grab a worker.
333 : */
334 : static struct Semaphore worker_sem;
335 :
336 : /**
337 : * Command-line options for various TALER_SECMOD_XXX_run() functions.
338 : */
339 : static struct TALER_SECMOD_Options *globals;
340 :
341 : /**
342 : * Where do we store the keys?
343 : */
344 : static char *keydir;
345 :
346 : /**
347 : * How much should coin creation (@e duration_withdraw) duration overlap
348 : * with the next denomination? Basically, the starting time of two
349 : * denominations is always @e duration_withdraw - #overlap_duration apart.
350 : */
351 : static struct GNUNET_TIME_Relative overlap_duration;
352 :
353 : /**
354 : * How long into the future do we pre-generate keys?
355 : */
356 : static struct GNUNET_TIME_Relative lookahead_sign;
357 :
358 : /**
359 : * All of our denominations, in a DLL. Sorted?
360 : */
361 : static struct Denomination *denom_head;
362 :
363 : /**
364 : * All of our denominations, in a DLL. Sorted?
365 : */
366 : static struct Denomination *denom_tail;
367 :
368 : /**
369 : * Map of hashes of public (CS) keys to `struct DenominationKey *`
370 : * with the respective private keys.
371 : */
372 : static struct GNUNET_CONTAINER_MultiHashMap *keys;
373 :
374 : /**
375 : * Task run to generate new keys.
376 : */
377 : static struct GNUNET_SCHEDULER_Task *keygen_task;
378 :
379 : /**
380 : * Lock for the keys queue.
381 : */
382 : static pthread_mutex_t keys_lock = PTHREAD_MUTEX_INITIALIZER;
383 :
384 : /**
385 : * Current key generation.
386 : */
387 : static uint64_t key_gen;
388 :
389 : /**
390 : * Generate the announcement message for @a dk.
391 : *
392 : * @param[in,out] dk denomination key to generate the announcement for
393 : */
394 : static void
395 225 : generate_response (struct DenominationKey *dk)
396 : {
397 225 : struct Denomination *denom = dk->denom;
398 225 : size_t nlen = strlen (denom->section) + 1;
399 : struct TALER_CRYPTO_CsKeyAvailableNotification *an;
400 : void *p;
401 : size_t tlen;
402 : struct GNUNET_TIME_Relative effective_duration;
403 :
404 : GNUNET_assert (sizeof(dk->denom_pub) < UINT16_MAX);
405 225 : GNUNET_assert (nlen < UINT16_MAX);
406 225 : tlen = nlen + sizeof (*an);
407 225 : GNUNET_assert (tlen < UINT16_MAX);
408 225 : an = GNUNET_malloc (tlen);
409 225 : an->header.size = htons ((uint16_t) tlen);
410 225 : an->header.type = htons (TALER_HELPER_CS_MT_AVAIL);
411 225 : an->section_name_len = htonl ((uint32_t) nlen);
412 225 : an->anchor_time = GNUNET_TIME_timestamp_hton (dk->anchor_start);
413 225 : effective_duration = GNUNET_TIME_absolute_get_difference (
414 : dk->anchor_start.abs_time,
415 : dk->anchor_end.abs_time);
416 225 : an->duration_withdraw = GNUNET_TIME_relative_hton (effective_duration);
417 225 : an->denom_pub = dk->denom_pub;
418 225 : TALER_exchange_secmod_cs_sign (&dk->h_cs,
419 225 : denom->section,
420 : dk->anchor_start,
421 : effective_duration,
422 : &TES_smpriv,
423 : &an->secm_sig);
424 225 : an->secm_pub = TES_smpub;
425 225 : p = (void *) &an[1];
426 225 : GNUNET_memcpy (p,
427 : denom->section,
428 : nlen);
429 225 : dk->an = an;
430 225 : }
431 :
432 :
433 : /**
434 : * Do the actual signing work.
435 : *
436 : * @param h_cs hash of key to sign with
437 : * @param planchet message to sign
438 : * @param for_melt true if for melting
439 : * @param[out] cs_sigp set to the CS signature
440 : * @return #TALER_EC_NONE on success
441 : */
442 : static enum TALER_ErrorCode
443 1173 : do_sign (const struct TALER_CsPubHashP *h_cs,
444 : const struct GNUNET_CRYPTO_CsBlindedMessage *planchet,
445 : bool for_melt,
446 : struct GNUNET_CRYPTO_CsBlindSignature *cs_sigp)
447 : {
448 : struct GNUNET_CRYPTO_CsRSecret r[2];
449 : struct DenominationKey *dk;
450 :
451 1173 : GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
452 1185 : dk = GNUNET_CONTAINER_multihashmap_get (keys,
453 : &h_cs->hash);
454 1185 : if (NULL == dk)
455 : {
456 3 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
457 3 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
458 : "Signing request failed, denomination key %s unknown\n",
459 : GNUNET_h2s (&h_cs->hash));
460 3 : return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
461 : }
462 1182 : if (dk->purge)
463 : {
464 : /* key was revoked, it must not be used for signing anymore */
465 0 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
466 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
467 : "Signing request failed, denomination key %s was revoked\n",
468 : GNUNET_h2s (&h_cs->hash));
469 0 : return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED;
470 : }
471 1182 : if (GNUNET_TIME_absolute_is_future (dk->anchor_start.abs_time))
472 : {
473 0 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
474 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
475 : "Signing request failed, denomination key %s is not yet valid\n",
476 : GNUNET_h2s (&h_cs->hash));
477 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY;
478 : }
479 1182 : if (GNUNET_TIME_absolute_is_past (dk->anchor_end.abs_time))
480 : {
481 : /* it is too late; now, usually we should never get here
482 : as we delete upon expiration, so this is just conservative */
483 0 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
484 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
485 : "Signing request failed, denomination key %s is expired (%llu)\n",
486 : GNUNET_h2s (&h_cs->hash),
487 : (unsigned long long) dk->anchor_end.abs_time.abs_value_us);
488 : /* usually we delete upon expiratoin, hence same EC */
489 0 : return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
490 : }
491 1182 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
492 : "Received request to sign over bytes with key %s\n",
493 : GNUNET_h2s (&h_cs->hash));
494 1182 : GNUNET_assert (dk->rc < UINT_MAX);
495 1182 : dk->rc++;
496 1182 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
497 1181 : GNUNET_CRYPTO_cs_r_derive (&planchet->nonce,
498 : for_melt ? "rm" : "rw",
499 1181 : &dk->denom_priv,
500 : r);
501 1180 : GNUNET_CRYPTO_cs_sign_derive (&dk->denom_priv,
502 : r,
503 : planchet,
504 : cs_sigp);
505 1171 : GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
506 1182 : GNUNET_assert (dk->rc > 0);
507 1182 : dk->rc--;
508 1182 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
509 1177 : return TALER_EC_NONE;
510 : }
511 :
512 :
513 : /**
514 : * Generate error response that signing failed.
515 : *
516 : * @param client client to send response to
517 : * @param ec error code to include
518 : * @return #GNUNET_OK on success
519 : */
520 : static enum GNUNET_GenericReturnValue
521 3 : fail_sign (struct TES_Client *client,
522 : enum TALER_ErrorCode ec)
523 : {
524 3 : struct TALER_CRYPTO_SignFailure sf = {
525 3 : .header.size = htons (sizeof (sf)),
526 3 : .header.type = htons (TALER_HELPER_CS_MT_RES_SIGN_FAILURE),
527 3 : .ec = htonl (ec)
528 : };
529 :
530 3 : return TES_transmit (client->csock,
531 : &sf.header);
532 : }
533 :
534 :
535 : /**
536 : * Generate error response that deriving failed.
537 : *
538 : * @param client client to send response to
539 : * @param ec error code to include
540 : * @return #GNUNET_OK on success
541 : */
542 : static enum GNUNET_GenericReturnValue
543 621 : fail_derive (struct TES_Client *client,
544 : enum TALER_ErrorCode ec)
545 : {
546 621 : struct TALER_CRYPTO_RDeriveFailure sf = {
547 621 : .header.size = htons (sizeof (sf)),
548 621 : .header.type = htons (TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE),
549 621 : .ec = htonl (ec)
550 : };
551 :
552 621 : return TES_transmit (client->csock,
553 : &sf.header);
554 : }
555 :
556 :
557 : /**
558 : * Generate signature response.
559 : *
560 : * @param client client to send response to
561 : * @param cs_answer signature to send
562 : * @return #GNUNET_OK on success
563 : */
564 : static enum GNUNET_GenericReturnValue
565 1176 : send_signature (struct TES_Client *client,
566 : const struct GNUNET_CRYPTO_CsBlindSignature *cs_answer)
567 : {
568 : struct TALER_CRYPTO_SignResponse sres;
569 :
570 1176 : sres.header.size = htons (sizeof (sres));
571 1176 : sres.header.type = htons (TALER_HELPER_CS_MT_RES_SIGNATURE);
572 1176 : sres.b = htonl (cs_answer->b);
573 1176 : sres.cs_answer = cs_answer->s_scalar;
574 1176 : return TES_transmit (client->csock,
575 : &sres.header);
576 : }
577 :
578 :
579 : /**
580 : * Handle @a client request @a sr to create signature. Create the
581 : * signature using the respective key and return the result to
582 : * the client.
583 : *
584 : * @param client the client making the request
585 : * @param sr the request details
586 : * @return #GNUNET_OK on success
587 : */
588 : static enum GNUNET_GenericReturnValue
589 0 : handle_sign_request (struct TES_Client *client,
590 : const struct TALER_CRYPTO_CsSignRequestMessage *sr)
591 : {
592 : struct GNUNET_CRYPTO_CsBlindSignature cs_answer;
593 0 : struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
594 : enum TALER_ErrorCode ec;
595 : enum GNUNET_GenericReturnValue ret;
596 :
597 0 : ec = do_sign (&sr->h_cs,
598 : &sr->message,
599 0 : (0 != ntohl (sr->for_melt)),
600 : &cs_answer);
601 0 : if (TALER_EC_NONE != ec)
602 : {
603 0 : return fail_sign (client,
604 : ec);
605 : }
606 0 : ret = send_signature (client,
607 : &cs_answer);
608 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
609 : "Sent CS signature after %s\n",
610 : GNUNET_TIME_relative2s (
611 : GNUNET_TIME_absolute_get_duration (now),
612 : GNUNET_YES));
613 0 : return ret;
614 : }
615 :
616 :
617 : /**
618 : * Do the actual deriving work.
619 : *
620 : * @param h_cs key to sign with
621 : * @param nonce nonce to derive from
622 : * @param for_melt true if for melting
623 : * @param[out] rpairp set to the derived values
624 : * @return #TALER_EC_NONE on success
625 : */
626 : static enum TALER_ErrorCode
627 1020 : do_derive (const struct TALER_CsPubHashP *h_cs,
628 : const struct GNUNET_CRYPTO_CsSessionNonce *nonce,
629 : bool for_melt,
630 : struct GNUNET_CRYPTO_CSPublicRPairP *rpairp)
631 : {
632 : struct DenominationKey *dk;
633 : struct GNUNET_CRYPTO_CSPrivateRPairP r_priv;
634 :
635 1020 : GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
636 1044 : dk = GNUNET_CONTAINER_multihashmap_get (keys,
637 : &h_cs->hash);
638 1044 : if (NULL == dk)
639 : {
640 1 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
641 1 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
642 : "R Derive request failed, denomination key %s unknown\n",
643 : GNUNET_h2s (&h_cs->hash));
644 1 : return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
645 : }
646 1043 : if (dk->purge)
647 : {
648 : /* key was revoked, it must not be used for deriving anymore */
649 8 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
650 8 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
651 : "R Derive request failed, denomination key %s was revoked\n",
652 : GNUNET_h2s (&h_cs->hash));
653 8 : return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED;
654 : }
655 1035 : if (GNUNET_TIME_absolute_is_future (dk->anchor_start.abs_time))
656 : {
657 612 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
658 612 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
659 : "R Derive request failed, denomination key %s is not yet valid\n",
660 : GNUNET_h2s (&h_cs->hash));
661 612 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY;
662 : }
663 423 : if (GNUNET_TIME_absolute_is_past (dk->anchor_end.abs_time))
664 : {
665 : /* it is too late; now, usually we should never get here
666 : as we delete upon expiration, so this is just conservative */
667 0 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
668 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
669 : "Signing request failed, denomination key %s is expired (%llu)\n",
670 : GNUNET_h2s (&h_cs->hash),
671 : (unsigned long long) dk->anchor_end.abs_time.abs_value_us);
672 : /* usually we delete upon expiratoin, hence same EC */
673 0 : return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
674 : }
675 423 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
676 : "Received request to derive R with key %s\n",
677 : GNUNET_h2s (&h_cs->hash));
678 423 : GNUNET_assert (dk->rc < UINT_MAX);
679 423 : dk->rc++;
680 423 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
681 423 : GNUNET_CRYPTO_cs_r_derive (nonce,
682 : for_melt ? "rm" : "rw",
683 423 : &dk->denom_priv,
684 : r_priv.r);
685 422 : GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
686 423 : GNUNET_assert (dk->rc > 0);
687 423 : dk->rc--;
688 423 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
689 419 : GNUNET_CRYPTO_cs_r_get_public (&r_priv.r[0],
690 : &rpairp->r_pub[0]);
691 421 : GNUNET_CRYPTO_cs_r_get_public (&r_priv.r[1],
692 : &rpairp->r_pub[1]);
693 420 : return TALER_EC_NONE;
694 : }
695 :
696 :
697 : /**
698 : * Generate derivation response.
699 : *
700 : * @param client client to send response to
701 : * @param r_pub public point value pair to send
702 : * @return #GNUNET_OK on success
703 : */
704 : static enum GNUNET_GenericReturnValue
705 423 : send_derivation (struct TES_Client *client,
706 : const struct GNUNET_CRYPTO_CSPublicRPairP *r_pub)
707 : {
708 423 : struct TALER_CRYPTO_RDeriveResponse rdr = {
709 423 : .header.size = htons (sizeof (rdr)),
710 423 : .header.type = htons (TALER_HELPER_CS_MT_RES_RDERIVE),
711 : .r_pub = *r_pub
712 : };
713 :
714 423 : return TES_transmit (client->csock,
715 : &rdr.header);
716 : }
717 :
718 :
719 : /**
720 : * Initialize a semaphore @a sem with a value of @a val.
721 : *
722 : * @param[out] sem semaphore to initialize
723 : * @param val initial value of the semaphore
724 : */
725 : static void
726 2566 : sem_init (struct Semaphore *sem,
727 : unsigned int val)
728 : {
729 2566 : GNUNET_assert (0 ==
730 : pthread_mutex_init (&sem->mutex,
731 : NULL));
732 2567 : GNUNET_assert (0 ==
733 : pthread_cond_init (&sem->cv,
734 : NULL));
735 2568 : sem->ctr = val;
736 2568 : }
737 :
738 :
739 : /**
740 : * Decrement semaphore, blocks until this is possible.
741 : *
742 : * @param[in,out] sem semaphore to decrement
743 : */
744 : static void
745 7235 : sem_down (struct Semaphore *sem)
746 : {
747 7235 : GNUNET_assert (0 == pthread_mutex_lock (&sem->mutex));
748 10999 : while (0 == sem->ctr)
749 : {
750 3704 : pthread_cond_wait (&sem->cv,
751 : &sem->mutex);
752 : }
753 7295 : sem->ctr--;
754 7295 : GNUNET_assert (0 == pthread_mutex_unlock (&sem->mutex));
755 7221 : }
756 :
757 :
758 : /**
759 : * Increment semaphore, blocks until this is possible.
760 : *
761 : * @param[in,out] sem semaphore to decrement
762 : */
763 : static void
764 7245 : sem_up (struct Semaphore *sem)
765 : {
766 7245 : GNUNET_assert (0 == pthread_mutex_lock (&sem->mutex));
767 7312 : sem->ctr++;
768 7312 : pthread_cond_signal (&sem->cv);
769 7266 : GNUNET_assert (0 == pthread_mutex_unlock (&sem->mutex));
770 7307 : }
771 :
772 :
773 : /**
774 : * Release resources used by @a sem.
775 : *
776 : * @param[in] sem semaphore to release (except the memory itself)
777 : */
778 : static void
779 2567 : sem_done (struct Semaphore *sem)
780 : {
781 2567 : GNUNET_break (0 == pthread_cond_destroy (&sem->cv));
782 2577 : GNUNET_break (0 == pthread_mutex_destroy (&sem->mutex));
783 2571 : }
784 :
785 :
786 : /**
787 : * Main logic of a worker thread. Grabs work, does it,
788 : * grabs more work.
789 : *
790 : * @param cls a `struct Worker *`
791 : * @returns cls
792 : */
793 : static void *
794 324 : worker (void *cls)
795 : {
796 324 : struct Worker *w = cls;
797 :
798 : while (true)
799 : {
800 2547 : GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
801 2553 : GNUNET_CONTAINER_DLL_insert (worker_head,
802 : worker_tail,
803 : w);
804 2553 : GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
805 2547 : sem_up (&worker_sem);
806 2546 : sem_down (&w->sem);
807 2519 : if (w->do_shutdown)
808 324 : break;
809 : {
810 2195 : struct BatchJob *bj = w->job;
811 :
812 2195 : switch (bj->type)
813 : {
814 1170 : case TYPE_SIGN:
815 : {
816 1170 : const struct TALER_CRYPTO_CsSignRequestMessage *sr
817 : = bj->details.sign.sr;
818 :
819 2351 : bj->ec = do_sign (&sr->h_cs,
820 : &sr->message,
821 1170 : (0 != ntohl (sr->for_melt)),
822 : &bj->details.sign.cs_answer);
823 1181 : break;
824 : }
825 1022 : case TYPE_RDERIVE:
826 : {
827 1022 : const struct TALER_CRYPTO_CsRDeriveRequest *rdr
828 : = bj->details.rderive.rdr;
829 2065 : bj->ec = do_derive (&rdr->h_cs,
830 : &rdr->nonce,
831 1022 : (0 != ntohl (rdr->for_melt)),
832 : &bj->details.rderive.rpairp);
833 1043 : break;
834 : }
835 : }
836 2227 : sem_up (&bj->sem);
837 2223 : w->job = NULL;
838 : }
839 : }
840 324 : return w;
841 : }
842 :
843 :
844 : /**
845 : * Start batch job @a bj to sign @a sr.
846 : *
847 : * @param sr signature request to answer
848 : * @param[out] bj job data structure
849 : */
850 : static void
851 1177 : start_sign_job (const struct TALER_CRYPTO_CsSignRequestMessage *sr,
852 : struct BatchJob *bj)
853 : {
854 1177 : sem_init (&bj->sem,
855 : 0);
856 1177 : bj->type = TYPE_SIGN;
857 1177 : bj->details.sign.sr = sr;
858 1177 : sem_down (&worker_sem);
859 1182 : GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
860 1185 : bj->worker = worker_head;
861 1185 : GNUNET_CONTAINER_DLL_remove (worker_head,
862 : worker_tail,
863 : bj->worker);
864 1185 : GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
865 1183 : bj->worker->job = bj;
866 1183 : sem_up (&bj->worker->sem);
867 1182 : }
868 :
869 :
870 : /**
871 : * Start batch job @a bj to derive @a rdr.
872 : *
873 : * @param rdr derivation request to answer
874 : * @param[out] bj job data structure
875 : */
876 : static void
877 1044 : start_derive_job (const struct TALER_CRYPTO_CsRDeriveRequest *rdr,
878 : struct BatchJob *bj)
879 : {
880 1044 : sem_init (&bj->sem,
881 : 0);
882 1044 : bj->type = TYPE_RDERIVE;
883 1044 : bj->details.rderive.rdr = rdr;
884 1044 : sem_down (&worker_sem);
885 1044 : GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
886 1044 : bj->worker = worker_head;
887 1044 : GNUNET_CONTAINER_DLL_remove (worker_head,
888 : worker_tail,
889 : bj->worker);
890 1044 : GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
891 1044 : bj->worker->job = bj;
892 1044 : sem_up (&bj->worker->sem);
893 1044 : }
894 :
895 :
896 : /**
897 : * Finish a job @a bj for a @a client.
898 : *
899 : * @param client who made the request
900 : * @param[in,out] bj job to finish
901 : * @return #GNUNET_OK on success, #GNUNET_SYSERR if we
902 : * failed to transmit the reply to @a client
903 : */
904 : static enum GNUNET_GenericReturnValue
905 2223 : finish_job (struct TES_Client *client,
906 : struct BatchJob *bj)
907 : {
908 2223 : sem_down (&bj->sem);
909 2221 : sem_done (&bj->sem);
910 2223 : switch (bj->type)
911 : {
912 1179 : case TYPE_SIGN:
913 1179 : if (TALER_EC_NONE != bj->ec)
914 3 : return fail_sign (client,
915 : bj->ec);
916 1176 : return send_signature (client,
917 1176 : &bj->details.sign.cs_answer);
918 1044 : case TYPE_RDERIVE:
919 1044 : if (TALER_EC_NONE != bj->ec)
920 621 : return fail_derive (client,
921 : bj->ec);
922 423 : return send_derivation (client,
923 423 : &bj->details.rderive.rpairp);
924 : }
925 0 : GNUNET_break (0);
926 0 : return GNUNET_SYSERR;
927 : }
928 :
929 :
930 : /**
931 : * Handle @a client request @a sr to create a batch of signature. Creates the
932 : * signatures using the respective key and return the results to the client.
933 : *
934 : * @param client the client making the request
935 : * @param bsr the request details
936 : * @return #GNUNET_OK on success
937 : */
938 : static enum GNUNET_GenericReturnValue
939 977 : handle_batch_sign_request (struct TES_Client *client,
940 : const struct TALER_CRYPTO_BatchSignRequest *bsr)
941 : {
942 977 : uint32_t bs = ntohl (bsr->batch_size);
943 977 : uint16_t size = ntohs (bsr->header.size) - sizeof (*bsr);
944 977 : const void *off = (const void *) &bsr[1];
945 977 : unsigned int idx = 0;
946 977 : bool failure = false;
947 977 : enum GNUNET_GenericReturnValue tret = GNUNET_OK;
948 :
949 977 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
950 : "Handling batch sign request of size %u\n",
951 : (unsigned int) bs);
952 977 : if (bs > TALER_MAX_COINS)
953 : {
954 0 : GNUNET_break_op (0);
955 0 : return GNUNET_SYSERR;
956 : }
957 977 : {
958 977 : struct BatchJob jobs[GNUNET_NZL (bs)];
959 :
960 2158 : while ( (idx < bs) &&
961 : (size >= sizeof (struct TALER_CRYPTO_CsSignRequestMessage)) )
962 : {
963 1173 : const struct TALER_CRYPTO_CsSignRequestMessage *sr = off;
964 1173 : uint16_t s = ntohs (sr->header.size);
965 :
966 1173 : if (s != sizeof (*sr))
967 : {
968 0 : failure = true;
969 0 : bs = idx;
970 0 : break;
971 : }
972 1173 : start_sign_job (sr,
973 1173 : &jobs[idx++]);
974 1181 : off += s;
975 1181 : size -= s;
976 : }
977 985 : GNUNET_break_op (0 == size);
978 981 : bs = GNUNET_MIN (bs,
979 : idx);
980 : /* Note: we must finish (and thus reap) *every* job we started,
981 : even once transmission failed, or we would leak workers. */
982 2159 : for (unsigned int i = 0; i<bs; i++)
983 1178 : if (GNUNET_OK !=
984 1179 : finish_job (client,
985 : &jobs[i]))
986 0 : tret = GNUNET_SYSERR;
987 : }
988 980 : if (GNUNET_OK != tret)
989 0 : return tret; /* client is gone, do not bother with more replies */
990 980 : if (failure)
991 : {
992 0 : struct TALER_CRYPTO_SignFailure sf = {
993 0 : .header.size = htons (sizeof (sf)),
994 0 : .header.type = htons (TALER_HELPER_CS_MT_RES_BATCH_SIGN_FAILURE),
995 0 : .ec = htonl (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE)
996 : };
997 :
998 0 : GNUNET_break (0);
999 0 : return TES_transmit (client->csock,
1000 : &sf.header);
1001 : }
1002 980 : return GNUNET_OK;
1003 : }
1004 :
1005 :
1006 : /**
1007 : * Handle @a client request @a sr to create a batch of derivations. Creates the
1008 : * derivations using the respective key and return the results to the client.
1009 : *
1010 : * @param client the client making the request
1011 : * @param bdr the request details
1012 : * @return #GNUNET_OK on success
1013 : */
1014 : static enum GNUNET_GenericReturnValue
1015 213 : handle_batch_derive_request (struct TES_Client *client,
1016 : const struct TALER_CRYPTO_BatchDeriveRequest *bdr)
1017 : {
1018 213 : uint32_t bs = ntohl (bdr->batch_size);
1019 213 : uint16_t size = ntohs (bdr->header.size) - sizeof (*bdr);
1020 213 : const void *off = (const void *) &bdr[1];
1021 213 : unsigned int idx = 0;
1022 213 : bool failure = false;
1023 213 : enum GNUNET_GenericReturnValue tret = GNUNET_OK;
1024 :
1025 213 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1026 : "Handling batch derivation request of size %u\n",
1027 : (unsigned int) bs);
1028 213 : if (bs > TALER_MAX_COINS)
1029 : {
1030 0 : GNUNET_break_op (0);
1031 0 : return GNUNET_SYSERR;
1032 : }
1033 213 : {
1034 213 : struct BatchJob jobs[GNUNET_NZL (bs)];
1035 :
1036 1257 : while ( (idx < bs) &&
1037 : (size >= sizeof (struct TALER_CRYPTO_CsRDeriveRequest)) )
1038 : {
1039 1044 : const struct TALER_CRYPTO_CsRDeriveRequest *rdr = off;
1040 1044 : uint16_t s = ntohs (rdr->header.size);
1041 :
1042 1044 : if ( (s > size) ||
1043 : (s != sizeof (*rdr)) )
1044 : {
1045 0 : failure = true;
1046 0 : bs = idx;
1047 0 : break;
1048 : }
1049 1044 : start_derive_job (rdr,
1050 1044 : &jobs[idx++]);
1051 1044 : off += s;
1052 1044 : size -= s;
1053 : }
1054 213 : GNUNET_break_op (0 == size);
1055 213 : bs = GNUNET_MIN (bs,
1056 : idx);
1057 : /* Note: we must finish (and thus reap) *every* job we started,
1058 : even once transmission failed, or we would leak workers. */
1059 1257 : for (unsigned int i = 0; i<bs; i++)
1060 1044 : if (GNUNET_OK !=
1061 1044 : finish_job (client,
1062 : &jobs[i]))
1063 0 : tret = GNUNET_SYSERR;
1064 : }
1065 213 : if (GNUNET_OK != tret)
1066 0 : return tret; /* client is gone, do not bother with more replies */
1067 213 : if (failure)
1068 : {
1069 0 : GNUNET_break (0);
1070 0 : return fail_derive (client,
1071 : TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE);
1072 : }
1073 213 : return GNUNET_OK;
1074 : }
1075 :
1076 :
1077 : /**
1078 : * Start worker thread for batch processing.
1079 : *
1080 : * @return #GNUNET_OK on success
1081 : */
1082 : static enum GNUNET_GenericReturnValue
1083 324 : start_worker (void)
1084 : {
1085 : struct Worker *w;
1086 :
1087 324 : w = GNUNET_new (struct Worker);
1088 324 : sem_init (&w->sem,
1089 : 0);
1090 324 : if (0 != pthread_create (&w->pt,
1091 : NULL,
1092 : &worker,
1093 : w))
1094 : {
1095 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1096 : "pthread_create");
1097 0 : GNUNET_free (w);
1098 0 : return GNUNET_SYSERR;
1099 : }
1100 324 : workers++;
1101 324 : return GNUNET_OK;
1102 : }
1103 :
1104 :
1105 : /**
1106 : * Stop all worker threads.
1107 : */
1108 : static void
1109 24 : stop_workers (void)
1110 : {
1111 348 : while (workers > 0)
1112 : {
1113 : struct Worker *w;
1114 : void *result;
1115 :
1116 324 : sem_down (&worker_sem);
1117 324 : GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
1118 324 : w = worker_head;
1119 324 : GNUNET_CONTAINER_DLL_remove (worker_head,
1120 : worker_tail,
1121 : w);
1122 324 : GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
1123 324 : w->do_shutdown = true;
1124 324 : sem_up (&w->sem);
1125 324 : pthread_join (w->pt,
1126 : &result);
1127 324 : GNUNET_assert (result == w);
1128 324 : sem_done (&w->sem);
1129 324 : GNUNET_free (w);
1130 324 : workers--;
1131 : }
1132 24 : }
1133 :
1134 :
1135 : /**
1136 : * Initialize key material for denomination key @a dk (also on disk).
1137 : *
1138 : * @param[in,out] dk denomination key to compute key material for
1139 : * @param position where in the DLL will the @a dk go
1140 : * @return #GNUNET_OK on success
1141 : */
1142 : static enum GNUNET_GenericReturnValue
1143 61 : setup_key (struct DenominationKey *dk,
1144 : struct DenominationKey *position)
1145 : {
1146 61 : struct Denomination *denom = dk->denom;
1147 : struct GNUNET_CRYPTO_CsPrivateKey priv;
1148 : struct GNUNET_CRYPTO_CsPublicKey pub;
1149 :
1150 61 : GNUNET_CRYPTO_cs_private_key_generate (&priv);
1151 61 : GNUNET_CRYPTO_cs_private_key_get_public (&priv,
1152 : &pub);
1153 61 : GNUNET_CRYPTO_hash (&pub,
1154 : sizeof (pub),
1155 : &dk->h_cs.hash);
1156 61 : GNUNET_asprintf (
1157 : &dk->filename,
1158 : "%s/%s/%llu-%llu",
1159 : keydir,
1160 : denom->section,
1161 61 : (unsigned long long) (dk->anchor_start.abs_time.abs_value_us
1162 61 : / GNUNET_TIME_UNIT_SECONDS.rel_value_us
1163 : ),
1164 61 : (unsigned long long) (dk->anchor_end.abs_time.abs_value_us
1165 61 : / GNUNET_TIME_UNIT_SECONDS.rel_value_us
1166 : ));
1167 61 : if (GNUNET_OK !=
1168 61 : GNUNET_DISK_fn_write (dk->filename,
1169 : &priv,
1170 : sizeof(priv),
1171 : GNUNET_DISK_PERM_USER_READ))
1172 : {
1173 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1174 : "write",
1175 : dk->filename);
1176 0 : return GNUNET_SYSERR;
1177 : }
1178 61 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1179 : "Setup fresh private key %s at %s in `%s' (generation #%llu)\n",
1180 : GNUNET_h2s (&dk->h_cs.hash),
1181 : GNUNET_TIME_timestamp2s (dk->anchor_start),
1182 : dk->filename,
1183 : (unsigned long long) key_gen);
1184 61 : dk->denom_priv = priv;
1185 61 : dk->denom_pub = pub;
1186 61 : dk->key_gen = key_gen;
1187 61 : generate_response (dk);
1188 61 : if (GNUNET_OK !=
1189 61 : GNUNET_CONTAINER_multihashmap_put (
1190 : keys,
1191 61 : &dk->h_cs.hash,
1192 : dk,
1193 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1194 : {
1195 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1196 : "Duplicate private key created! Terminating.\n");
1197 0 : GNUNET_free (dk->filename);
1198 0 : GNUNET_free (dk->an);
1199 0 : GNUNET_free (dk);
1200 0 : return GNUNET_SYSERR;
1201 : }
1202 61 : GNUNET_CONTAINER_DLL_insert_after (denom->keys_head,
1203 : denom->keys_tail,
1204 : position,
1205 : dk);
1206 61 : return GNUNET_OK;
1207 : }
1208 :
1209 :
1210 : /**
1211 : * The withdraw period of a key @a dk has expired. Purge it.
1212 : *
1213 : * @param[in] dk expired denomination key to purge
1214 : */
1215 : static void
1216 12 : purge_key (struct DenominationKey *dk)
1217 : {
1218 12 : if (dk->purge)
1219 0 : return;
1220 12 : if (0 != unlink (dk->filename))
1221 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1222 : "unlink",
1223 : dk->filename);
1224 12 : GNUNET_free (dk->filename);
1225 12 : dk->purge = true;
1226 12 : dk->key_gen = key_gen;
1227 : }
1228 :
1229 :
1230 : /**
1231 : * A @a client informs us that a key has been revoked.
1232 : * Check if the key is still in use, and if so replace (!)
1233 : * it with a fresh key.
1234 : *
1235 : * @param client the client making the request
1236 : * @param rr the revocation request
1237 : */
1238 : static enum GNUNET_GenericReturnValue
1239 13 : handle_revoke_request (struct TES_Client *client,
1240 : const struct TALER_CRYPTO_CsRevokeRequest *rr)
1241 : {
1242 : struct DenominationKey *dk;
1243 : struct DenominationKey *ndk;
1244 : struct Denomination *denom;
1245 :
1246 : (void) client;
1247 13 : GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
1248 13 : dk = GNUNET_CONTAINER_multihashmap_get (keys,
1249 : &rr->h_cs.hash);
1250 13 : if (NULL == dk)
1251 : {
1252 0 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
1253 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1254 : "Revocation request ignored, denomination key %s unknown\n",
1255 : GNUNET_h2s (&rr->h_cs.hash));
1256 0 : return GNUNET_OK;
1257 : }
1258 13 : if (dk->purge)
1259 : {
1260 1 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
1261 1 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1262 : "Revocation request ignored, denomination key %s already revoked\n",
1263 : GNUNET_h2s (&rr->h_cs.hash));
1264 1 : return GNUNET_OK;
1265 : }
1266 :
1267 12 : key_gen++;
1268 12 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1269 : "Revoking key %s, bumping generation to %llu\n",
1270 : GNUNET_h2s (&rr->h_cs.hash),
1271 : (unsigned long long) key_gen);
1272 12 : purge_key (dk);
1273 :
1274 : /* Setup replacement key */
1275 12 : denom = dk->denom;
1276 12 : ndk = GNUNET_new (struct DenominationKey);
1277 12 : ndk->denom = denom;
1278 12 : ndk->anchor_start = dk->anchor_start;
1279 12 : ndk->anchor_end = dk->anchor_end;
1280 12 : if (GNUNET_OK !=
1281 12 : setup_key (ndk,
1282 : dk))
1283 : {
1284 0 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
1285 0 : GNUNET_break (0);
1286 0 : GNUNET_SCHEDULER_shutdown ();
1287 0 : globals->global_ret = EXIT_FAILURE;
1288 0 : return GNUNET_SYSERR;
1289 : }
1290 12 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
1291 12 : TES_wake_clients ();
1292 12 : return GNUNET_OK;
1293 : }
1294 :
1295 :
1296 : /**
1297 : * Handle @a client request @a rdr to create signature. Create the
1298 : * signature using the respective key and return the result to
1299 : * the client.
1300 : *
1301 : * @param client the client making the request
1302 : * @param rdr the request details
1303 : * @return #GNUNET_OK on success
1304 : */
1305 : static enum GNUNET_GenericReturnValue
1306 0 : handle_r_derive_request (struct TES_Client *client,
1307 : const struct TALER_CRYPTO_CsRDeriveRequest *rdr)
1308 : {
1309 : struct GNUNET_CRYPTO_CSPublicRPairP r_pub;
1310 0 : struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1311 : enum TALER_ErrorCode ec;
1312 : enum GNUNET_GenericReturnValue ret;
1313 :
1314 0 : ec = do_derive (&rdr->h_cs,
1315 : &rdr->nonce,
1316 0 : (0 != ntohl (rdr->for_melt)),
1317 : &r_pub);
1318 0 : if (TALER_EC_NONE != ec)
1319 : {
1320 0 : return fail_derive (client,
1321 : ec);
1322 : }
1323 :
1324 0 : ret = send_derivation (client,
1325 : &r_pub);
1326 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1327 : "Sent CS Derived R after %s\n",
1328 : GNUNET_TIME_relative2s (
1329 : GNUNET_TIME_absolute_get_duration (now),
1330 : GNUNET_YES));
1331 0 : return ret;
1332 : }
1333 :
1334 :
1335 : /**
1336 : * Handle @a hdr message received from @a client.
1337 : *
1338 : * @param client the client that received the message
1339 : * @param hdr message that was received
1340 : * @return #GNUNET_OK on success
1341 : */
1342 : static enum GNUNET_GenericReturnValue
1343 1209 : cs_work_dispatch (struct TES_Client *client,
1344 : const struct GNUNET_MessageHeader *hdr)
1345 : {
1346 1209 : uint16_t msize = ntohs (hdr->size);
1347 :
1348 1209 : switch (ntohs (hdr->type))
1349 : {
1350 0 : case TALER_HELPER_CS_MT_REQ_SIGN:
1351 0 : if (msize < sizeof (struct TALER_CRYPTO_CsSignRequestMessage))
1352 : {
1353 0 : GNUNET_break_op (0);
1354 0 : return GNUNET_SYSERR;
1355 : }
1356 0 : return handle_sign_request (
1357 : client,
1358 : (const struct TALER_CRYPTO_CsSignRequestMessage *) hdr);
1359 13 : case TALER_HELPER_CS_MT_REQ_REVOKE:
1360 13 : if (msize != sizeof (struct TALER_CRYPTO_CsRevokeRequest))
1361 : {
1362 0 : GNUNET_break_op (0);
1363 0 : return GNUNET_SYSERR;
1364 : }
1365 13 : return handle_revoke_request (
1366 : client,
1367 : (const struct TALER_CRYPTO_CsRevokeRequest *) hdr);
1368 982 : case TALER_HELPER_CS_MT_REQ_BATCH_SIGN:
1369 982 : if (msize <= sizeof (struct TALER_CRYPTO_BatchSignRequest))
1370 : {
1371 0 : GNUNET_break_op (0);
1372 0 : return GNUNET_SYSERR;
1373 : }
1374 982 : return handle_batch_sign_request (
1375 : client,
1376 : (const struct TALER_CRYPTO_BatchSignRequest *) hdr);
1377 213 : case TALER_HELPER_CS_MT_REQ_BATCH_RDERIVE:
1378 213 : if (msize <= sizeof (struct TALER_CRYPTO_BatchDeriveRequest))
1379 : {
1380 0 : GNUNET_break_op (0);
1381 0 : return GNUNET_SYSERR;
1382 : }
1383 213 : return handle_batch_derive_request (
1384 : client,
1385 : (const struct TALER_CRYPTO_BatchDeriveRequest *) hdr);
1386 0 : case TALER_HELPER_CS_MT_REQ_RDERIVE:
1387 0 : if (msize != sizeof (struct TALER_CRYPTO_CsRDeriveRequest))
1388 : {
1389 0 : GNUNET_break_op (0);
1390 0 : return GNUNET_SYSERR;
1391 : }
1392 0 : return handle_r_derive_request (client,
1393 : (const struct
1394 : TALER_CRYPTO_CsRDeriveRequest *) hdr);
1395 1 : default:
1396 1 : GNUNET_break_op (0);
1397 0 : return GNUNET_SYSERR;
1398 : }
1399 : }
1400 :
1401 :
1402 : /**
1403 : * Send our initial key set to @a client together with the
1404 : * "sync" terminator.
1405 : *
1406 : * @param client the client to inform
1407 : * @return #GNUNET_OK on success
1408 : */
1409 : static enum GNUNET_GenericReturnValue
1410 32 : cs_client_init (struct TES_Client *client)
1411 : {
1412 32 : size_t obs = 0;
1413 : char *buf;
1414 :
1415 32 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1416 : "Initializing new client %p\n",
1417 : client);
1418 32 : GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
1419 32 : for (struct Denomination *denom = denom_head;
1420 107 : NULL != denom;
1421 75 : denom = denom->next)
1422 : {
1423 75 : for (struct DenominationKey *dk = denom->keys_head;
1424 344 : NULL != dk;
1425 269 : dk = dk->next)
1426 : {
1427 269 : obs += ntohs (dk->an->header.size);
1428 : }
1429 : }
1430 32 : buf = GNUNET_malloc (obs);
1431 32 : obs = 0;
1432 32 : for (struct Denomination *denom = denom_head;
1433 107 : NULL != denom;
1434 75 : denom = denom->next)
1435 : {
1436 75 : for (struct DenominationKey *dk = denom->keys_head;
1437 344 : NULL != dk;
1438 269 : dk = dk->next)
1439 : {
1440 269 : GNUNET_memcpy (&buf[obs],
1441 : dk->an,
1442 : ntohs (dk->an->header.size));
1443 269 : obs += ntohs (dk->an->header.size);
1444 : }
1445 : }
1446 32 : client->key_gen = key_gen;
1447 32 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
1448 32 : if (GNUNET_OK !=
1449 32 : TES_transmit_raw (client->csock,
1450 : obs,
1451 : buf))
1452 : {
1453 0 : GNUNET_free (buf);
1454 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1455 : "Client %p must have disconnected\n",
1456 : client);
1457 0 : return GNUNET_SYSERR;
1458 : }
1459 32 : GNUNET_free (buf);
1460 : {
1461 32 : struct GNUNET_MessageHeader synced = {
1462 32 : .type = htons (TALER_HELPER_CS_SYNCED),
1463 32 : .size = htons (sizeof (synced))
1464 : };
1465 :
1466 32 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1467 : "Sending CS SYNCED message to %p\n",
1468 : client);
1469 32 : if (GNUNET_OK !=
1470 32 : TES_transmit (client->csock,
1471 : &synced))
1472 : {
1473 0 : GNUNET_break (0);
1474 0 : return GNUNET_SYSERR;
1475 : }
1476 : }
1477 32 : return GNUNET_OK;
1478 : }
1479 :
1480 :
1481 : /**
1482 : * Notify @a client about all changes to the keys since
1483 : * the last generation known to the @a client.
1484 : *
1485 : * @param client the client to notify
1486 : * @return #GNUNET_OK on success
1487 : */
1488 : static enum GNUNET_GenericReturnValue
1489 32 : cs_update_client_keys (struct TES_Client *client)
1490 : {
1491 32 : size_t obs = 0;
1492 : char *buf;
1493 : enum GNUNET_GenericReturnValue ret;
1494 :
1495 32 : GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
1496 32 : for (struct Denomination *denom = denom_head;
1497 180 : NULL != denom;
1498 148 : denom = denom->next)
1499 : {
1500 148 : for (struct DenominationKey *key = denom->keys_head;
1501 639 : NULL != key;
1502 491 : key = key->next)
1503 : {
1504 491 : if (key->key_gen <= client->key_gen)
1505 464 : continue;
1506 27 : if (key->purge)
1507 12 : obs += sizeof (struct TALER_CRYPTO_CsKeyPurgeNotification);
1508 : else
1509 15 : obs += ntohs (key->an->header.size);
1510 : }
1511 : }
1512 32 : if (0 == obs)
1513 : {
1514 : /* nothing to do */
1515 17 : client->key_gen = key_gen;
1516 17 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
1517 17 : return GNUNET_OK;
1518 : }
1519 15 : buf = GNUNET_malloc (obs);
1520 15 : obs = 0;
1521 15 : for (struct Denomination *denom = denom_head;
1522 111 : NULL != denom;
1523 96 : denom = denom->next)
1524 : {
1525 96 : for (struct DenominationKey *key = denom->keys_head;
1526 419 : NULL != key;
1527 323 : key = key->next)
1528 : {
1529 323 : if (key->key_gen <= client->key_gen)
1530 296 : continue;
1531 27 : if (key->purge)
1532 : {
1533 12 : struct TALER_CRYPTO_CsKeyPurgeNotification pn = {
1534 12 : .header.type = htons (TALER_HELPER_CS_MT_PURGE),
1535 12 : .header.size = htons (sizeof (pn)),
1536 : .h_cs = key->h_cs
1537 : };
1538 :
1539 12 : GNUNET_memcpy (&buf[obs],
1540 : &pn,
1541 : sizeof (pn));
1542 12 : GNUNET_assert (obs + sizeof (pn)
1543 : > obs);
1544 12 : obs += sizeof (pn);
1545 : }
1546 : else
1547 : {
1548 15 : GNUNET_memcpy (&buf[obs],
1549 : key->an,
1550 : ntohs (key->an->header.size));
1551 15 : GNUNET_assert (obs + ntohs (key->an->header.size)
1552 : > obs);
1553 15 : obs += ntohs (key->an->header.size);
1554 : }
1555 : }
1556 : }
1557 15 : client->key_gen = key_gen;
1558 15 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
1559 15 : ret = TES_transmit_raw (client->csock,
1560 : obs,
1561 : buf);
1562 15 : GNUNET_free (buf);
1563 15 : return ret;
1564 : }
1565 :
1566 :
1567 : /**
1568 : * Create a new denomination key (we do not have enough).
1569 : *
1570 : * @param[in,out] denom denomination key to create
1571 : * @param anchor_start when to start key signing validity
1572 : * @param anchor_end when to end key signing validity
1573 : * @return #GNUNET_OK on success
1574 : */
1575 : static enum GNUNET_GenericReturnValue
1576 49 : create_key (struct Denomination *denom,
1577 : struct GNUNET_TIME_Timestamp anchor_start,
1578 : struct GNUNET_TIME_Timestamp anchor_end)
1579 : {
1580 : struct DenominationKey *dk;
1581 :
1582 49 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1583 : "Creating new key for `%s' with start date %s\n",
1584 : denom->section,
1585 : GNUNET_TIME_timestamp2s (anchor_start));
1586 49 : dk = GNUNET_new (struct DenominationKey);
1587 49 : dk->denom = denom;
1588 49 : dk->anchor_start = anchor_start;
1589 49 : dk->anchor_end = anchor_end;
1590 49 : if (GNUNET_OK !=
1591 49 : setup_key (dk,
1592 : denom->keys_tail))
1593 : {
1594 0 : GNUNET_break (0);
1595 0 : GNUNET_free (dk);
1596 0 : GNUNET_SCHEDULER_shutdown ();
1597 0 : globals->global_ret = EXIT_FAILURE;
1598 0 : return GNUNET_SYSERR;
1599 : }
1600 49 : return GNUNET_OK;
1601 : }
1602 :
1603 :
1604 : /**
1605 : * Obtain the maximum withdraw duration of all denominations.
1606 : *
1607 : * Must only be called while the #keys_lock is held.
1608 : *
1609 : * @return maximum withdraw duration, zero if there are no denominations
1610 : */
1611 : static struct GNUNET_TIME_Relative
1612 56 : get_maximum_duration (void)
1613 : {
1614 56 : struct GNUNET_TIME_Relative ret
1615 : = GNUNET_TIME_UNIT_ZERO;
1616 :
1617 56 : for (struct Denomination *denom = denom_head;
1618 263 : NULL != denom;
1619 207 : denom = denom->next)
1620 : {
1621 207 : ret = GNUNET_TIME_relative_max (ret,
1622 : denom->duration_withdraw);
1623 : }
1624 56 : return ret;
1625 : }
1626 :
1627 :
1628 : /**
1629 : * At what time do we need to next create keys if we just did?
1630 : *
1631 : * @return time when to next create keys if we just finished key generation
1632 : */
1633 : static struct GNUNET_TIME_Absolute
1634 16 : action_time (void)
1635 : {
1636 16 : struct GNUNET_TIME_Relative md = get_maximum_duration ();
1637 16 : struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1638 : uint64_t mod;
1639 :
1640 16 : if (GNUNET_TIME_relative_is_zero (md))
1641 0 : return GNUNET_TIME_UNIT_FOREVER_ABS;
1642 16 : mod = now.abs_value_us % md.rel_value_us;
1643 16 : now.abs_value_us -= mod;
1644 16 : return GNUNET_TIME_absolute_add (now,
1645 : md);
1646 : }
1647 :
1648 :
1649 : /**
1650 : * Remove all denomination keys of @a denom that have expired.
1651 : *
1652 : * @param[in,out] denom denomination family to remove keys for
1653 : */
1654 : static void
1655 274 : remove_expired_denomination_keys (struct Denomination *denom)
1656 : {
1657 546 : while ( (NULL != denom->keys_head) &&
1658 266 : GNUNET_TIME_absolute_is_past (
1659 266 : denom->keys_head->anchor_end.abs_time) )
1660 : {
1661 6 : struct DenominationKey *key = denom->keys_head;
1662 6 : struct DenominationKey *nxt = key->next;
1663 :
1664 6 : if (0 != key->rc)
1665 0 : break; /* later */
1666 6 : GNUNET_CONTAINER_DLL_remove (denom->keys_head,
1667 : denom->keys_tail,
1668 : key);
1669 6 : GNUNET_assert (GNUNET_OK ==
1670 : GNUNET_CONTAINER_multihashmap_remove (
1671 : keys,
1672 : &key->h_cs.hash,
1673 : key));
1674 12 : if ( (! key->purge) &&
1675 6 : (0 != unlink (key->filename)) )
1676 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1677 : "unlink",
1678 : key->filename);
1679 6 : GNUNET_free (key->filename);
1680 6 : GNUNET_free (key->an);
1681 6 : GNUNET_free (key);
1682 6 : key = nxt;
1683 : }
1684 274 : }
1685 :
1686 :
1687 : /**
1688 : * Obtain the end anchor to use at this point. Uses the
1689 : * #lookahead_sign and then rounds it up by the maximum
1690 : * duration of any denomination to arrive at a globally
1691 : * valid end-date.
1692 : *
1693 : * Must only be called while the #keys_lock is held.
1694 : *
1695 : * @return end anchor
1696 : */
1697 : static struct GNUNET_TIME_Timestamp
1698 40 : get_anchor_end (void)
1699 : {
1700 40 : struct GNUNET_TIME_Relative md = get_maximum_duration ();
1701 : struct GNUNET_TIME_Absolute end
1702 40 : = GNUNET_TIME_relative_to_absolute (lookahead_sign);
1703 : uint64_t mod;
1704 :
1705 40 : if (GNUNET_TIME_relative_is_zero (md))
1706 11 : return GNUNET_TIME_UNIT_ZERO_TS;
1707 : /* Round up 'end' to a multiple of 'md' */
1708 29 : mod = end.abs_value_us % md.rel_value_us;
1709 29 : end.abs_value_us -= mod;
1710 29 : return GNUNET_TIME_absolute_to_timestamp (
1711 : GNUNET_TIME_absolute_add (end,
1712 : md));
1713 : }
1714 :
1715 :
1716 : /**
1717 : * Create all denomination keys that are required for our
1718 : * desired lookahead and that we do not yet have.
1719 : *
1720 : * @param[in,out] opt our options
1721 : * @param[in,out] wake set to true if we should wake the clients
1722 : */
1723 : static void
1724 40 : create_missing_keys (struct TALER_SECMOD_Options *opt,
1725 : bool *wake)
1726 : {
1727 : struct GNUNET_TIME_Timestamp start;
1728 : struct GNUNET_TIME_Timestamp end;
1729 :
1730 40 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1731 : "Updating denominations ...\n");
1732 40 : start = opt->global_now;
1733 40 : GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
1734 40 : end = get_anchor_end ();
1735 40 : for (struct Denomination *denom = denom_head;
1736 177 : NULL != denom;
1737 137 : denom = denom->next)
1738 : {
1739 : struct GNUNET_TIME_Timestamp anchor_start;
1740 : struct GNUNET_TIME_Timestamp anchor_end;
1741 : struct GNUNET_TIME_Timestamp next_end;
1742 137 : bool finished = false;
1743 :
1744 137 : remove_expired_denomination_keys (denom);
1745 137 : if (NULL != denom->keys_tail)
1746 : {
1747 123 : anchor_start = denom->keys_tail->anchor_end;
1748 123 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1749 : "Expanding keys of denomination `%s', last key %s valid for another %s\n",
1750 : denom->section,
1751 : GNUNET_h2s (&denom->keys_tail->h_cs.hash),
1752 : GNUNET_TIME_relative2s (
1753 : GNUNET_TIME_absolute_get_remaining (
1754 : anchor_start.abs_time),
1755 : true));
1756 : }
1757 : else
1758 : {
1759 14 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1760 : "Starting keys of denomination `%s'\n",
1761 : denom->section);
1762 : /* Round the very first anchor down to the configured calendar
1763 : interval; subsequent anchors inherit the alignment from the
1764 : (rounded up) end of the preceding key. The UTC variants are used
1765 : so that the result does not depend on the time zone the secmod
1766 : happens to run in. */
1767 14 : anchor_start = GNUNET_TIME_absolute_to_timestamp (
1768 : GNUNET_TIME_round_down_utc (start.abs_time,
1769 : denom->anchor_round));
1770 : }
1771 137 : finished = GNUNET_TIME_timestamp_cmp (anchor_start,
1772 : >=,
1773 : end);
1774 186 : while (! finished)
1775 : {
1776 : /* Round the end of the validity period up to the configured calendar
1777 : interval. As #GNUNET_TIME_UNIT_YEARS is 365 days, this is also what
1778 : keeps the anchors from drifting off the calendar boundary across leap
1779 : years. Without ANCHOR_ROUND, all of this is a no-op. */
1780 49 : anchor_end = GNUNET_TIME_absolute_to_timestamp (
1781 : GNUNET_TIME_round_up_utc (
1782 : GNUNET_TIME_absolute_add (anchor_start.abs_time,
1783 : denom->duration_withdraw),
1784 : denom->anchor_round));
1785 49 : next_end = GNUNET_TIME_absolute_to_timestamp (
1786 : GNUNET_TIME_round_up_utc (
1787 : GNUNET_TIME_absolute_add (anchor_end.abs_time,
1788 : denom->duration_withdraw),
1789 : denom->anchor_round));
1790 49 : if (GNUNET_TIME_timestamp_cmp (next_end,
1791 : >,
1792 : end))
1793 : {
1794 : /* With ANCHOR_ROUND set the calendar interval already provides the
1795 : alignment, and stretching the last key would make it cover more
1796 : than the one interval it is supposed to cover. */
1797 17 : if (GNUNET_TIME_RI_NONE == denom->anchor_round)
1798 16 : anchor_end = end; /* extend period to align end periods */
1799 17 : finished = true;
1800 : }
1801 : /* adjust start time down to ensure overlap */
1802 49 : anchor_start = GNUNET_TIME_absolute_to_timestamp (
1803 : GNUNET_TIME_absolute_subtract (anchor_start.abs_time,
1804 : overlap_duration));
1805 49 : if (! *wake)
1806 : {
1807 3 : key_gen++;
1808 3 : *wake = true;
1809 : }
1810 49 : if (GNUNET_OK !=
1811 49 : create_key (denom,
1812 : anchor_start,
1813 : anchor_end))
1814 : {
1815 0 : GNUNET_break (0);
1816 0 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
1817 0 : globals->global_ret = EXIT_FAILURE;
1818 0 : GNUNET_SCHEDULER_shutdown ();
1819 0 : return;
1820 : }
1821 49 : anchor_start = anchor_end;
1822 : }
1823 137 : remove_expired_denomination_keys (denom);
1824 : }
1825 40 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
1826 40 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1827 : "Updating denominations finished ...\n");
1828 : }
1829 :
1830 :
1831 : /**
1832 : * Task run periodically to expire keys and/or generate fresh ones.
1833 : *
1834 : * @param cls the `struct TALER_SECMOD_Options *`
1835 : */
1836 : static void
1837 16 : update_denominations (void *cls)
1838 : {
1839 16 : struct TALER_SECMOD_Options *opt = cls;
1840 : struct GNUNET_TIME_Absolute at;
1841 16 : bool wake = false;
1842 :
1843 : (void) cls;
1844 16 : keygen_task = NULL;
1845 16 : opt->global_now = GNUNET_TIME_timestamp_get ();
1846 16 : create_missing_keys (opt,
1847 : &wake);
1848 16 : if (wake)
1849 3 : TES_wake_clients ();
1850 16 : at = action_time ();
1851 16 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1852 : "Next key generation due at %s\n",
1853 : GNUNET_TIME_absolute2s (at));
1854 16 : keygen_task = GNUNET_SCHEDULER_add_at (at,
1855 : &update_denominations,
1856 : opt);
1857 16 : }
1858 :
1859 :
1860 : /**
1861 : * Parse private key of denomination @a denom in @a buf.
1862 : *
1863 : * @param[out] denom denomination of the key
1864 : * @param filename name of the file we are parsing, for logging
1865 : * @param priv key material
1866 : */
1867 : static void
1868 164 : parse_key (struct Denomination *denom,
1869 : const char *filename,
1870 : const struct GNUNET_CRYPTO_CsPrivateKey *priv)
1871 : {
1872 : const char *anchor_s;
1873 : char dummy;
1874 : unsigned long long anchor_start_ll;
1875 : unsigned long long anchor_end_ll;
1876 : struct GNUNET_TIME_Timestamp anchor_start;
1877 : struct GNUNET_TIME_Timestamp anchor_end;
1878 164 : char *nf = NULL;
1879 :
1880 164 : anchor_s = strrchr (filename,
1881 : '/');
1882 164 : if (NULL == anchor_s)
1883 : {
1884 : /* File in a directory without '/' in the name, this makes no sense. */
1885 0 : GNUNET_break (0);
1886 0 : return;
1887 : }
1888 164 : anchor_s++;
1889 164 : if (2 != sscanf (anchor_s,
1890 : "%llu-%llu%c",
1891 : &anchor_start_ll,
1892 : &anchor_end_ll,
1893 : &dummy))
1894 : {
1895 : /* try legacy mode */
1896 3 : if (1 != sscanf (anchor_s,
1897 : "%llu%c",
1898 : &anchor_start_ll,
1899 : &dummy))
1900 : {
1901 : /* Filenames in KEYDIR must ONLY be the anchor time in seconds! */
1902 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1903 : "Filename `%s' invalid for key file, skipping\n",
1904 : anchor_s);
1905 0 : return;
1906 : }
1907 : anchor_start.abs_time.abs_value_us
1908 3 : = anchor_start_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us;
1909 6 : if (anchor_start_ll != anchor_start.abs_time.abs_value_us
1910 3 : / GNUNET_TIME_UNIT_SECONDS.rel_value_us)
1911 : {
1912 : /* Integer overflow. Bad, invalid filename. */
1913 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1914 : "Integer overflow. Filename `%s' invalid for key file, skipping\n",
1915 : anchor_s);
1916 0 : return;
1917 : }
1918 : anchor_end
1919 3 : = GNUNET_TIME_absolute_to_timestamp (
1920 : GNUNET_TIME_absolute_add (anchor_start.abs_time,
1921 : denom->duration_withdraw));
1922 3 : GNUNET_asprintf (
1923 : &nf,
1924 : "%s/%s/%llu-%llu",
1925 : keydir,
1926 : denom->section,
1927 : anchor_start_ll,
1928 3 : (unsigned long long) (anchor_end.abs_time.abs_value_us
1929 3 : / GNUNET_TIME_UNIT_SECONDS.rel_value_us));
1930 : /* Try to fix the legacy filename */
1931 3 : if (0 !=
1932 3 : rename (filename,
1933 : nf))
1934 : {
1935 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
1936 : "rename",
1937 : filename);
1938 0 : GNUNET_free (nf);
1939 : }
1940 : }
1941 : else
1942 : {
1943 : anchor_start.abs_time.abs_value_us
1944 161 : = anchor_start_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us;
1945 : anchor_end.abs_time.abs_value_us
1946 161 : = anchor_end_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us;
1947 322 : if ( (anchor_start_ll != anchor_start.abs_time.abs_value_us
1948 161 : / GNUNET_TIME_UNIT_SECONDS.rel_value_us) ||
1949 322 : (anchor_end_ll != anchor_end.abs_time.abs_value_us
1950 161 : / GNUNET_TIME_UNIT_SECONDS.rel_value_us) )
1951 : {
1952 : /* Integer overflow. Bad, invalid filename. */
1953 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1954 : "Integer overflow. Filename `%s' invalid for key file, skipping\n",
1955 : anchor_s);
1956 0 : return;
1957 : }
1958 : }
1959 :
1960 : {
1961 : struct DenominationKey *dk;
1962 : struct DenominationKey *before;
1963 :
1964 164 : dk = GNUNET_new (struct DenominationKey);
1965 164 : dk->denom_priv = *priv;
1966 164 : dk->denom = denom;
1967 164 : dk->anchor_start = anchor_start;
1968 164 : dk->anchor_end = anchor_end;
1969 164 : dk->filename = (NULL == nf) ? GNUNET_strdup (filename) : nf;
1970 164 : GNUNET_CRYPTO_cs_private_key_get_public (priv,
1971 : &dk->denom_pub);
1972 164 : GNUNET_CRYPTO_hash (&dk->denom_pub,
1973 : sizeof (dk->denom_pub),
1974 : &dk->h_cs.hash);
1975 164 : generate_response (dk);
1976 164 : if (GNUNET_OK !=
1977 164 : GNUNET_CONTAINER_multihashmap_put (
1978 : keys,
1979 164 : &dk->h_cs.hash,
1980 : dk,
1981 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1982 : {
1983 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1984 : "Duplicate private key %s detected in file `%s'. Skipping.\n",
1985 : GNUNET_h2s (&dk->h_cs.hash),
1986 : filename);
1987 0 : GNUNET_free (dk->an);
1988 0 : GNUNET_free (dk);
1989 0 : return;
1990 : }
1991 164 : before = NULL;
1992 164 : for (struct DenominationKey *pos = denom->keys_head;
1993 195 : NULL != pos;
1994 31 : pos = pos->next)
1995 : {
1996 125 : if (GNUNET_TIME_timestamp_cmp (pos->anchor_start,
1997 : >,
1998 : anchor_start))
1999 94 : break;
2000 31 : before = pos;
2001 : }
2002 164 : GNUNET_CONTAINER_DLL_insert_after (denom->keys_head,
2003 : denom->keys_tail,
2004 : before,
2005 : dk);
2006 164 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2007 : "Imported key %s from `%s'\n",
2008 : GNUNET_h2s (&dk->h_cs.hash),
2009 : filename);
2010 : }
2011 : }
2012 :
2013 :
2014 : /**
2015 : * Import a private key from @a filename for the denomination
2016 : * given in @a cls.
2017 : *
2018 : * @param[in,out] cls a `struct Denomiantion`
2019 : * @param filename name of a file in the directory
2020 : * @return #GNUNET_OK (always, continue to iterate)
2021 : */
2022 : static enum GNUNET_GenericReturnValue
2023 164 : import_key (void *cls,
2024 : const char *filename)
2025 : {
2026 164 : struct Denomination *denom = cls;
2027 : struct GNUNET_DISK_FileHandle *fh;
2028 : struct GNUNET_DISK_MapHandle *map;
2029 : void *ptr;
2030 : int fd;
2031 : struct stat sbuf;
2032 :
2033 164 : fd = TES_open_key_file (filename,
2034 : &sbuf);
2035 164 : if (-1 == fd)
2036 0 : return GNUNET_OK;
2037 164 : fh = GNUNET_DISK_get_handle_from_int_fd (fd);
2038 164 : if (NULL == fh)
2039 : {
2040 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
2041 : "open",
2042 : filename);
2043 0 : GNUNET_break (0 == close (fd));
2044 0 : return GNUNET_OK;
2045 : }
2046 164 : if (sbuf.st_size != sizeof(struct GNUNET_CRYPTO_CsPrivateKey))
2047 : {
2048 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2049 : "File `%s' too big to be a private key\n",
2050 : filename);
2051 0 : GNUNET_DISK_file_close (fh);
2052 0 : return GNUNET_OK;
2053 : }
2054 164 : ptr = GNUNET_DISK_file_map (fh,
2055 : &map,
2056 : GNUNET_DISK_MAP_TYPE_READ,
2057 164 : (size_t) sbuf.st_size);
2058 164 : if (NULL == ptr)
2059 : {
2060 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
2061 : "mmap",
2062 : filename);
2063 0 : GNUNET_DISK_file_close (fh);
2064 0 : return GNUNET_OK;
2065 : }
2066 164 : parse_key (denom,
2067 : filename,
2068 : (const struct GNUNET_CRYPTO_CsPrivateKey *) ptr);
2069 164 : GNUNET_DISK_file_unmap (map);
2070 164 : GNUNET_DISK_file_close (fh);
2071 164 : return GNUNET_OK;
2072 : }
2073 :
2074 :
2075 : /**
2076 : * Parse configuration for denomination type parameters. Also determines
2077 : * our anchor by looking at the existing denominations of the same type.
2078 : *
2079 : * @param cfg configuration to use
2080 : * @param ct section in the configuration file giving the denomination type parameters
2081 : * @param[out] denom set to the denomination parameters from the configuration
2082 : * @return #GNUNET_OK on success, #GNUNET_SYSERR if the configuration is invalid
2083 : */
2084 : static enum GNUNET_GenericReturnValue
2085 67 : parse_denomination_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg,
2086 : const char *ct,
2087 : struct Denomination *denom)
2088 : {
2089 : char *secname;
2090 :
2091 67 : GNUNET_asprintf (&secname,
2092 : "%s-secmod-cs",
2093 67 : globals->section);
2094 67 : if (GNUNET_OK !=
2095 67 : GNUNET_CONFIGURATION_get_value_time (cfg,
2096 : ct,
2097 : "DURATION_WITHDRAW",
2098 : &denom->duration_withdraw))
2099 : {
2100 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2101 : ct,
2102 : "DURATION_WITHDRAW");
2103 0 : GNUNET_free (secname);
2104 0 : return GNUNET_SYSERR;
2105 : }
2106 67 : if (GNUNET_TIME_relative_cmp (denom->duration_withdraw,
2107 : <,
2108 : GNUNET_TIME_UNIT_SECONDS))
2109 : {
2110 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2111 : ct,
2112 : "DURATION_WITHDRAW",
2113 : "less than one second is not supported");
2114 0 : GNUNET_free (secname);
2115 0 : return GNUNET_SYSERR;
2116 : }
2117 67 : if (GNUNET_TIME_relative_cmp (overlap_duration,
2118 : >=,
2119 : denom->duration_withdraw))
2120 : {
2121 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2122 : secname,
2123 : "OVERLAP_DURATION",
2124 : "Value given must be smaller than value for DURATION_WITHDRAW!");
2125 0 : GNUNET_free (secname);
2126 0 : return GNUNET_SYSERR;
2127 : }
2128 : {
2129 : struct GNUNET_TIME_Relative ar;
2130 :
2131 : /* The denomination section takes precedence, the secmod section
2132 : provides the default for all denominations. */
2133 67 : if ( (GNUNET_OK !=
2134 67 : GNUNET_CONFIGURATION_get_value_time (cfg,
2135 : ct,
2136 : "ANCHOR_ROUND",
2137 63 : &ar)) &&
2138 : (GNUNET_OK !=
2139 63 : GNUNET_CONFIGURATION_get_value_time (cfg,
2140 : secname,
2141 : "ANCHOR_ROUND",
2142 : &ar)) )
2143 0 : ar = GNUNET_TIME_UNIT_ZERO; /* not configured: do not round */
2144 : denom->anchor_round
2145 67 : = GNUNET_TIME_relative_to_round_interval (ar);
2146 67 : if ( (GNUNET_TIME_RI_NONE == denom->anchor_round) &&
2147 63 : (! GNUNET_TIME_relative_is_zero (ar)) )
2148 : {
2149 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2150 : ct,
2151 : "ANCHOR_ROUND",
2152 : "Value given must be zero or exactly one second, minute, hour, day, week, month, quarter or year");
2153 0 : GNUNET_free (secname);
2154 0 : return GNUNET_SYSERR;
2155 : }
2156 : }
2157 67 : GNUNET_free (secname);
2158 67 : denom->section = TES_normalize_section (ct);
2159 67 : return GNUNET_OK;
2160 : }
2161 :
2162 :
2163 : /**
2164 : * Closure for #load_denominations.
2165 : */
2166 : struct LoadContext
2167 : {
2168 :
2169 : /**
2170 : * Configuration to use.
2171 : */
2172 : const struct GNUNET_CONFIGURATION_Handle *cfg;
2173 :
2174 : /**
2175 : * Current time to use.
2176 : */
2177 : struct GNUNET_TIME_Timestamp t;
2178 :
2179 : /**
2180 : * Configuration section prefix to use for denomination settings.
2181 : * "coin_" for the exchange, "doco_" for Donau.
2182 : */
2183 : const char *cprefix;
2184 :
2185 : /**
2186 : * Status, to be set to #GNUNET_SYSERR on failure
2187 : */
2188 : enum GNUNET_GenericReturnValue ret;
2189 : };
2190 :
2191 :
2192 : /**
2193 : * Generate new denomination signing keys for the denomination type of the given @a
2194 : * denomination_alias.
2195 : *
2196 : * @param cls a `struct LoadContext`, with 'ret' to be set to #GNUNET_SYSERR on failure
2197 : * @param denomination_alias name of the denomination's section in the configuration
2198 : */
2199 : static void
2200 1027 : load_denominations (void *cls,
2201 : const char *denomination_alias)
2202 : {
2203 1027 : struct LoadContext *ctx = cls;
2204 : struct Denomination *denom;
2205 : char *cipher;
2206 :
2207 1027 : if (0 != strncasecmp (denomination_alias,
2208 : ctx->cprefix,
2209 : strlen (ctx->cprefix)))
2210 960 : return; /* not a denomination type definition */
2211 141 : if (GNUNET_OK !=
2212 141 : GNUNET_CONFIGURATION_get_value_string (ctx->cfg,
2213 : denomination_alias,
2214 : "CIPHER",
2215 : &cipher))
2216 : {
2217 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2218 : denomination_alias,
2219 : "CIPHER");
2220 0 : return;
2221 : }
2222 141 : if (0 != strcmp (cipher, "CS"))
2223 : {
2224 74 : GNUNET_free (cipher);
2225 74 : return; /* Ignore denominations of other types than CS*/
2226 : }
2227 67 : GNUNET_free (cipher);
2228 :
2229 67 : denom = GNUNET_new (struct Denomination);
2230 67 : if (GNUNET_OK !=
2231 67 : parse_denomination_cfg (ctx->cfg,
2232 : denomination_alias,
2233 : denom))
2234 : {
2235 0 : ctx->ret = GNUNET_SYSERR;
2236 0 : GNUNET_free (denom);
2237 0 : return;
2238 : }
2239 67 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2240 : "Loading keys for denomination %s\n",
2241 : denom->section);
2242 : {
2243 : char *dname;
2244 :
2245 67 : GNUNET_asprintf (&dname,
2246 : "%s/%s",
2247 : keydir,
2248 : denom->section);
2249 67 : GNUNET_break (GNUNET_OK ==
2250 : GNUNET_DISK_directory_create (dname));
2251 67 : GNUNET_DISK_directory_scan (dname,
2252 : &import_key,
2253 : denom);
2254 67 : GNUNET_free (dname);
2255 : }
2256 67 : GNUNET_CONTAINER_DLL_insert (denom_head,
2257 : denom_tail,
2258 : denom);
2259 : }
2260 :
2261 :
2262 : /**
2263 : * Load the various duration values from @a cfg
2264 : *
2265 : * @param cfg configuration to use
2266 : * @return #GNUNET_OK on success
2267 : */
2268 : static enum GNUNET_GenericReturnValue
2269 37 : load_durations (const struct GNUNET_CONFIGURATION_Handle *cfg)
2270 : {
2271 : char *secname;
2272 :
2273 37 : GNUNET_asprintf (&secname,
2274 : "%s-secmod-cs",
2275 37 : globals->section);
2276 37 : if (GNUNET_OK !=
2277 37 : GNUNET_CONFIGURATION_get_value_time (cfg,
2278 : secname,
2279 : "OVERLAP_DURATION",
2280 : &overlap_duration))
2281 : {
2282 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2283 : secname,
2284 : "OVERLAP_DURATION");
2285 0 : GNUNET_free (secname);
2286 0 : return GNUNET_SYSERR;
2287 : }
2288 37 : if (GNUNET_OK !=
2289 37 : GNUNET_CONFIGURATION_get_value_time (cfg,
2290 : secname,
2291 : "LOOKAHEAD_SIGN",
2292 : &lookahead_sign))
2293 : {
2294 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2295 : secname,
2296 : "LOOKAHEAD_SIGN");
2297 0 : GNUNET_free (secname);
2298 0 : return GNUNET_SYSERR;
2299 : }
2300 37 : GNUNET_free (secname);
2301 37 : return GNUNET_OK;
2302 : }
2303 :
2304 :
2305 : /**
2306 : * Function run on shutdown. Stops the various jobs (nicely).
2307 : *
2308 : * @param cls a `struct TALER_SECMOD_Options`
2309 : */
2310 : static void
2311 24 : do_shutdown (void *cls)
2312 : {
2313 : (void) cls;
2314 24 : TES_listen_stop ();
2315 24 : if (NULL != keygen_task)
2316 : {
2317 13 : GNUNET_SCHEDULER_cancel (keygen_task);
2318 13 : keygen_task = NULL;
2319 : }
2320 24 : stop_workers ();
2321 24 : sem_done (&worker_sem);
2322 24 : }
2323 :
2324 :
2325 : void
2326 37 : TALER_SECMOD_cs_run (void *cls,
2327 : char *const *args,
2328 : const char *cfgfile,
2329 : const struct GNUNET_CONFIGURATION_Handle *cfg)
2330 : {
2331 : static struct TES_Callbacks cb = {
2332 : .dispatch = &cs_work_dispatch,
2333 : .updater = &cs_update_client_keys,
2334 : .init = &cs_client_init
2335 : };
2336 37 : struct TALER_SECMOD_Options *opt = cls;
2337 : char *secname;
2338 :
2339 : (void) args;
2340 : (void) cfgfile;
2341 37 : globals = opt;
2342 37 : if (GNUNET_TIME_timestamp_cmp (opt->global_now,
2343 : !=,
2344 : opt->global_now_tmp))
2345 : {
2346 : /* The user gave "--now", use it! */
2347 0 : opt->global_now = opt->global_now_tmp;
2348 : }
2349 : else
2350 : {
2351 : /* get current time again, we may be timetraveling! */
2352 37 : opt->global_now = GNUNET_TIME_timestamp_get ();
2353 : }
2354 37 : GNUNET_asprintf (&secname,
2355 : "%s-secmod-cs",
2356 : opt->section);
2357 37 : if (GNUNET_OK !=
2358 37 : GNUNET_CONFIGURATION_get_value_filename (cfg,
2359 : secname,
2360 : "KEY_DIR",
2361 : &keydir))
2362 : {
2363 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2364 : secname,
2365 : "KEY_DIR");
2366 0 : GNUNET_free (secname);
2367 0 : opt->global_ret = EXIT_NOTCONFIGURED;
2368 24 : return;
2369 : }
2370 37 : if (GNUNET_OK !=
2371 37 : load_durations (cfg))
2372 : {
2373 0 : opt->global_ret = EXIT_NOTCONFIGURED;
2374 0 : GNUNET_free (secname);
2375 0 : return;
2376 : }
2377 37 : if (GNUNET_OK !=
2378 37 : TES_normalize_key_directory (cfg,
2379 : keydir,
2380 : opt->cprefix))
2381 : {
2382 13 : opt->global_ret = EXIT_FAILURE;
2383 13 : GNUNET_free (secname);
2384 13 : return;
2385 : }
2386 24 : opt->global_ret = TES_listen_start (cfg,
2387 : secname,
2388 : &cb);
2389 24 : GNUNET_free (secname);
2390 24 : if (0 != opt->global_ret)
2391 0 : return;
2392 24 : sem_init (&worker_sem,
2393 : 0);
2394 24 : GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
2395 : opt);
2396 24 : if (0 == opt->max_workers)
2397 : {
2398 : long lret;
2399 :
2400 0 : lret = sysconf (_SC_NPROCESSORS_CONF);
2401 0 : if (lret <= 0)
2402 0 : lret = 1;
2403 0 : opt->max_workers = (unsigned int) lret;
2404 : }
2405 348 : for (unsigned int i = 0; i<opt->max_workers; i++)
2406 324 : if (GNUNET_OK !=
2407 324 : start_worker ())
2408 : {
2409 0 : GNUNET_SCHEDULER_shutdown ();
2410 0 : return;
2411 : }
2412 : /* Load denominations */
2413 24 : keys = GNUNET_CONTAINER_multihashmap_create (65536,
2414 : true);
2415 : {
2416 24 : struct LoadContext lc = {
2417 : .cfg = cfg,
2418 : .ret = GNUNET_OK,
2419 : .t = opt->global_now,
2420 24 : .cprefix = opt->cprefix
2421 : };
2422 24 : bool wake = true;
2423 :
2424 24 : GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
2425 24 : GNUNET_CONFIGURATION_iterate_sections (cfg,
2426 : &load_denominations,
2427 : &lc);
2428 24 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
2429 24 : if (GNUNET_OK != lc.ret)
2430 : {
2431 0 : opt->global_ret = EXIT_FAILURE;
2432 0 : GNUNET_SCHEDULER_shutdown ();
2433 0 : return;
2434 : }
2435 24 : create_missing_keys (opt,
2436 : &wake);
2437 : }
2438 24 : if (NULL == denom_head)
2439 : {
2440 11 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2441 : "No CS denominations configured. Make sure section names start with `%s' if you are using CS!\n",
2442 : opt->cprefix);
2443 11 : TES_wake_clients ();
2444 11 : return;
2445 : }
2446 : /* start job to keep keys up-to-date; MUST be run before the #listen_task,
2447 : hence with priority. */
2448 13 : keygen_task = GNUNET_SCHEDULER_add_with_priority (
2449 : GNUNET_SCHEDULER_PRIORITY_URGENT,
2450 : &update_denominations,
2451 : opt);
2452 : }
|