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