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 186 : generate_response (struct DenominationKey *dk)
396 : {
397 186 : struct Denomination *denom = dk->denom;
398 186 : 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 186 : GNUNET_assert (nlen < UINT16_MAX);
406 186 : tlen = nlen + sizeof (*an);
407 186 : GNUNET_assert (tlen < UINT16_MAX);
408 186 : an = GNUNET_malloc (tlen);
409 186 : an->header.size = htons ((uint16_t) tlen);
410 186 : an->header.type = htons (TALER_HELPER_CS_MT_AVAIL);
411 186 : an->section_name_len = htonl ((uint32_t) nlen);
412 186 : an->anchor_time = GNUNET_TIME_timestamp_hton (dk->anchor_start);
413 186 : effective_duration = GNUNET_TIME_absolute_get_difference (
414 : dk->anchor_start.abs_time,
415 : dk->anchor_end.abs_time);
416 186 : an->duration_withdraw = GNUNET_TIME_relative_hton (effective_duration);
417 186 : an->denom_pub = dk->denom_pub;
418 186 : TALER_exchange_secmod_cs_sign (&dk->h_cs,
419 186 : denom->section,
420 : dk->anchor_start,
421 : effective_duration,
422 : &TES_smpriv,
423 : &an->secm_sig);
424 186 : an->secm_pub = TES_smpub;
425 186 : p = (void *) &an[1];
426 186 : GNUNET_memcpy (p,
427 : denom->section,
428 : nlen);
429 186 : dk->an = an;
430 186 : }
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 1128 : 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 1128 : GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
452 1152 : dk = GNUNET_CONTAINER_multihashmap_get (keys,
453 : &h_cs->hash);
454 1152 : 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 1149 : 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 1149 : 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 1149 : 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 1149 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
492 : "Received request to sign over bytes with key %s\n",
493 : GNUNET_h2s (&h_cs->hash));
494 1149 : GNUNET_assert (dk->rc < UINT_MAX);
495 1149 : dk->rc++;
496 1149 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
497 1149 : GNUNET_CRYPTO_cs_r_derive (&planchet->nonce,
498 : for_melt ? "rm" : "rw",
499 1149 : &dk->denom_priv,
500 : r);
501 1149 : GNUNET_CRYPTO_cs_sign_derive (&dk->denom_priv,
502 : r,
503 : planchet,
504 : cs_sigp);
505 1146 : GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
506 1149 : GNUNET_assert (dk->rc > 0);
507 1149 : dk->rc--;
508 1149 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
509 1147 : 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 1142 : send_signature (struct TES_Client *client,
566 : const struct GNUNET_CRYPTO_CsBlindSignature *cs_answer)
567 : {
568 : struct TALER_CRYPTO_SignResponse sres;
569 :
570 1142 : sres.header.size = htons (sizeof (sres));
571 1142 : sres.header.type = htons (TALER_HELPER_CS_MT_RES_SIGNATURE);
572 1142 : sres.b = htonl (cs_answer->b);
573 1142 : sres.cs_answer = cs_answer->s_scalar;
574 1142 : 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 961 : 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 961 : GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
636 978 : dk = GNUNET_CONTAINER_multihashmap_get (keys,
637 : &h_cs->hash);
638 978 : 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 977 : 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 969 : 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 611 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY;
662 : }
663 357 : 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 357 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
676 : "Received request to derive R with key %s\n",
677 : GNUNET_h2s (&h_cs->hash));
678 357 : GNUNET_assert (dk->rc < UINT_MAX);
679 357 : dk->rc++;
680 357 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
681 357 : GNUNET_CRYPTO_cs_r_derive (nonce,
682 : for_melt ? "rm" : "rw",
683 357 : &dk->denom_priv,
684 : r_priv.r);
685 357 : GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
686 357 : GNUNET_assert (dk->rc > 0);
687 357 : dk->rc--;
688 357 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
689 357 : GNUNET_CRYPTO_cs_r_get_public (&r_priv.r[0],
690 : &rpairp->r_pub[0]);
691 354 : GNUNET_CRYPTO_cs_r_get_public (&r_priv.r[1],
692 : &rpairp->r_pub[1]);
693 353 : 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 357 : send_derivation (struct TES_Client *client,
706 : const struct GNUNET_CRYPTO_CSPublicRPairP *r_pub)
707 : {
708 357 : struct TALER_CRYPTO_RDeriveResponse rdr = {
709 357 : .header.size = htons (sizeof (rdr)),
710 357 : .header.type = htons (TALER_HELPER_CS_MT_RES_RDERIVE),
711 : .r_pub = *r_pub
712 : };
713 :
714 357 : 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 2434 : sem_init (struct Semaphore *sem,
727 : unsigned int val)
728 : {
729 2434 : GNUNET_assert (0 ==
730 : pthread_mutex_init (&sem->mutex,
731 : NULL));
732 2434 : GNUNET_assert (0 ==
733 : pthread_cond_init (&sem->cv,
734 : NULL));
735 2436 : sem->ctr = val;
736 2436 : }
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 6897 : sem_down (struct Semaphore *sem)
746 : {
747 6897 : GNUNET_assert (0 == pthread_mutex_lock (&sem->mutex));
748 10432 : while (0 == sem->ctr)
749 : {
750 3506 : pthread_cond_wait (&sem->cv,
751 : &sem->mutex);
752 : }
753 6926 : sem->ctr--;
754 6926 : GNUNET_assert (0 == pthread_mutex_unlock (&sem->mutex));
755 6937 : }
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 6885 : sem_up (struct Semaphore *sem)
765 : {
766 6885 : GNUNET_assert (0 == pthread_mutex_lock (&sem->mutex));
767 6939 : sem->ctr++;
768 6939 : pthread_cond_signal (&sem->cv);
769 6909 : GNUNET_assert (0 == pthread_mutex_unlock (&sem->mutex));
770 6936 : }
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 2439 : sem_done (struct Semaphore *sem)
780 : {
781 2439 : GNUNET_break (0 == pthread_cond_destroy (&sem->cv));
782 2444 : GNUNET_break (0 == pthread_mutex_destroy (&sem->mutex));
783 2443 : }
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 292 : worker (void *cls)
795 : {
796 292 : struct Worker *w = cls;
797 :
798 : while (true)
799 : {
800 2414 : GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
801 2422 : GNUNET_CONTAINER_DLL_insert (worker_head,
802 : worker_tail,
803 : w);
804 2422 : GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
805 2421 : sem_up (&worker_sem);
806 2419 : sem_down (&w->sem);
807 2406 : if (w->do_shutdown)
808 292 : break;
809 : {
810 2114 : struct BatchJob *bj = w->job;
811 :
812 2114 : switch (bj->type)
813 : {
814 1140 : case TYPE_SIGN:
815 : {
816 1140 : const struct TALER_CRYPTO_CsSignRequestMessage *sr
817 : = bj->details.sign.sr;
818 :
819 2289 : bj->ec = do_sign (&sr->h_cs,
820 : &sr->message,
821 1140 : (0 != ntohl (sr->for_melt)),
822 : &bj->details.sign.cs_answer);
823 1149 : break;
824 : }
825 960 : case TYPE_RDERIVE:
826 : {
827 960 : const struct TALER_CRYPTO_CsRDeriveRequest *rdr
828 : = bj->details.rderive.rdr;
829 1934 : bj->ec = do_derive (&rdr->h_cs,
830 : &rdr->nonce,
831 960 : (0 != ntohl (rdr->for_melt)),
832 : &bj->details.rderive.rpairp);
833 974 : break;
834 : }
835 : }
836 2137 : sem_up (&bj->sem);
837 2122 : w->job = NULL;
838 : }
839 : }
840 292 : 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 1143 : start_sign_job (const struct TALER_CRYPTO_CsSignRequestMessage *sr,
852 : struct BatchJob *bj)
853 : {
854 1143 : sem_init (&bj->sem,
855 : 0);
856 1140 : bj->type = TYPE_SIGN;
857 1140 : bj->details.sign.sr = sr;
858 1140 : sem_down (&worker_sem);
859 1150 : GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
860 1152 : bj->worker = worker_head;
861 1152 : GNUNET_CONTAINER_DLL_remove (worker_head,
862 : worker_tail,
863 : bj->worker);
864 1152 : GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
865 1152 : bj->worker->job = bj;
866 1152 : sem_up (&bj->worker->sem);
867 1150 : }
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 978 : start_derive_job (const struct TALER_CRYPTO_CsRDeriveRequest *rdr,
878 : struct BatchJob *bj)
879 : {
880 978 : sem_init (&bj->sem,
881 : 0);
882 978 : bj->type = TYPE_RDERIVE;
883 978 : bj->details.rderive.rdr = rdr;
884 978 : sem_down (&worker_sem);
885 978 : GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
886 978 : bj->worker = worker_head;
887 978 : GNUNET_CONTAINER_DLL_remove (worker_head,
888 : worker_tail,
889 : bj->worker);
890 978 : GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
891 978 : bj->worker->job = bj;
892 978 : sem_up (&bj->worker->sem);
893 978 : }
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 : */
902 : static void
903 2125 : finish_job (struct TES_Client *client,
904 : struct BatchJob *bj)
905 : {
906 2125 : sem_down (&bj->sem);
907 2129 : sem_done (&bj->sem);
908 2129 : switch (bj->type)
909 : {
910 1149 : case TYPE_SIGN:
911 1149 : if (TALER_EC_NONE != bj->ec)
912 : {
913 3 : fail_sign (client,
914 : bj->ec);
915 3 : return;
916 : }
917 1146 : send_signature (client,
918 1146 : &bj->details.sign.cs_answer);
919 1138 : break;
920 978 : case TYPE_RDERIVE:
921 978 : if (TALER_EC_NONE != bj->ec)
922 : {
923 621 : fail_derive (client,
924 : bj->ec);
925 621 : return;
926 : }
927 357 : send_derivation (client,
928 357 : &bj->details.rderive.rpairp);
929 357 : break;
930 : }
931 : }
932 :
933 :
934 : /**
935 : * Handle @a client request @a sr to create a batch of signature. Creates the
936 : * signatures using the respective key and return the results to the client.
937 : *
938 : * @param client the client making the request
939 : * @param bsr the request details
940 : * @return #GNUNET_OK on success
941 : */
942 : static enum GNUNET_GenericReturnValue
943 947 : handle_batch_sign_request (struct TES_Client *client,
944 : const struct TALER_CRYPTO_BatchSignRequest *bsr)
945 : {
946 947 : uint32_t bs = ntohl (bsr->batch_size);
947 947 : uint16_t size = ntohs (bsr->header.size) - sizeof (*bsr);
948 947 : const void *off = (const void *) &bsr[1];
949 947 : unsigned int idx = 0;
950 947 : bool failure = false;
951 :
952 947 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
953 : "Handling batch sign request of size %u\n",
954 : (unsigned int) bs);
955 947 : if (bs > TALER_MAX_COINS)
956 : {
957 0 : GNUNET_break_op (0);
958 0 : return GNUNET_SYSERR;
959 : }
960 947 : {
961 947 : struct BatchJob jobs[GNUNET_NZL (bs)];
962 :
963 2094 : while ( (idx < bs) &&
964 : (size >= sizeof (struct TALER_CRYPTO_CsSignRequestMessage)) )
965 : {
966 1139 : const struct TALER_CRYPTO_CsSignRequestMessage *sr = off;
967 1139 : uint16_t s = ntohs (sr->header.size);
968 :
969 1139 : if (s != sizeof (*sr))
970 : {
971 0 : failure = true;
972 0 : bs = idx;
973 0 : break;
974 : }
975 1139 : start_sign_job (sr,
976 1139 : &jobs[idx++]);
977 1147 : off += s;
978 1147 : size -= s;
979 : }
980 955 : GNUNET_break_op (0 == size);
981 954 : bs = GNUNET_MIN (bs,
982 : idx);
983 2094 : for (unsigned int i = 0; i<bs; i++)
984 1147 : finish_job (client,
985 : &jobs[i]);
986 : }
987 947 : if (failure)
988 : {
989 0 : struct TALER_CRYPTO_SignFailure sf = {
990 0 : .header.size = htons (sizeof (sf)),
991 0 : .header.type = htons (TALER_HELPER_CS_MT_RES_BATCH_SIGN_FAILURE),
992 0 : .ec = htonl (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE)
993 : };
994 :
995 0 : GNUNET_break (0);
996 0 : return TES_transmit (client->csock,
997 : &sf.header);
998 : }
999 947 : return GNUNET_OK;
1000 : }
1001 :
1002 :
1003 : /**
1004 : * Handle @a client request @a sr to create a batch of derivations. Creates the
1005 : * derivations using the respective key and return the results to the client.
1006 : *
1007 : * @param client the client making the request
1008 : * @param bdr the request details
1009 : * @return #GNUNET_OK on success
1010 : */
1011 : static enum GNUNET_GenericReturnValue
1012 157 : handle_batch_derive_request (struct TES_Client *client,
1013 : const struct TALER_CRYPTO_BatchDeriveRequest *bdr)
1014 : {
1015 157 : uint32_t bs = ntohl (bdr->batch_size);
1016 157 : uint16_t size = ntohs (bdr->header.size) - sizeof (*bdr);
1017 157 : const void *off = (const void *) &bdr[1];
1018 157 : unsigned int idx = 0;
1019 157 : bool failure = false;
1020 :
1021 157 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1022 : "Handling batch derivation request of size %u\n",
1023 : (unsigned int) bs);
1024 157 : if (bs > TALER_MAX_COINS)
1025 : {
1026 0 : GNUNET_break_op (0);
1027 0 : return GNUNET_SYSERR;
1028 : }
1029 157 : {
1030 157 : struct BatchJob jobs[GNUNET_NZL (bs)];
1031 :
1032 1135 : while ( (idx < bs) &&
1033 : (size >= sizeof (struct TALER_CRYPTO_CsRDeriveRequest)) )
1034 : {
1035 978 : const struct TALER_CRYPTO_CsRDeriveRequest *rdr = off;
1036 978 : uint16_t s = ntohs (rdr->header.size);
1037 :
1038 978 : if ( (s > size) ||
1039 : (s != sizeof (*rdr)) )
1040 : {
1041 0 : failure = true;
1042 0 : bs = idx;
1043 0 : break;
1044 : }
1045 978 : start_derive_job (rdr,
1046 978 : &jobs[idx++]);
1047 978 : off += s;
1048 978 : size -= s;
1049 : }
1050 157 : GNUNET_break_op (0 == size);
1051 157 : bs = GNUNET_MIN (bs,
1052 : idx);
1053 1135 : for (unsigned int i = 0; i<bs; i++)
1054 978 : finish_job (client,
1055 : &jobs[i]);
1056 : }
1057 157 : if (failure)
1058 : {
1059 0 : GNUNET_break (0);
1060 0 : return fail_derive (client,
1061 : TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE);
1062 : }
1063 157 : return GNUNET_OK;
1064 : }
1065 :
1066 :
1067 : /**
1068 : * Start worker thread for batch processing.
1069 : *
1070 : * @return #GNUNET_OK on success
1071 : */
1072 : static enum GNUNET_GenericReturnValue
1073 292 : start_worker (void)
1074 : {
1075 : struct Worker *w;
1076 :
1077 292 : w = GNUNET_new (struct Worker);
1078 292 : sem_init (&w->sem,
1079 : 0);
1080 292 : if (0 != pthread_create (&w->pt,
1081 : NULL,
1082 : &worker,
1083 : w))
1084 : {
1085 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
1086 : "pthread_create");
1087 0 : GNUNET_free (w);
1088 0 : return GNUNET_SYSERR;
1089 : }
1090 292 : workers++;
1091 292 : return GNUNET_OK;
1092 : }
1093 :
1094 :
1095 : /**
1096 : * Stop all worker threads.
1097 : */
1098 : static void
1099 22 : stop_workers (void)
1100 : {
1101 314 : while (workers > 0)
1102 : {
1103 : struct Worker *w;
1104 : void *result;
1105 :
1106 292 : sem_down (&worker_sem);
1107 292 : GNUNET_assert (0 == pthread_mutex_lock (&worker_lock));
1108 292 : w = worker_head;
1109 292 : GNUNET_CONTAINER_DLL_remove (worker_head,
1110 : worker_tail,
1111 : w);
1112 292 : GNUNET_assert (0 == pthread_mutex_unlock (&worker_lock));
1113 292 : w->do_shutdown = true;
1114 292 : sem_up (&w->sem);
1115 292 : pthread_join (w->pt,
1116 : &result);
1117 292 : GNUNET_assert (result == w);
1118 292 : sem_done (&w->sem);
1119 292 : GNUNET_free (w);
1120 292 : workers--;
1121 : }
1122 22 : }
1123 :
1124 :
1125 : /**
1126 : * Initialize key material for denomination key @a dk (also on disk).
1127 : *
1128 : * @param[in,out] dk denomination key to compute key material for
1129 : * @param position where in the DLL will the @a dk go
1130 : * @return #GNUNET_OK on success
1131 : */
1132 : static enum GNUNET_GenericReturnValue
1133 52 : setup_key (struct DenominationKey *dk,
1134 : struct DenominationKey *position)
1135 : {
1136 52 : struct Denomination *denom = dk->denom;
1137 : struct GNUNET_CRYPTO_CsPrivateKey priv;
1138 : struct GNUNET_CRYPTO_CsPublicKey pub;
1139 :
1140 52 : GNUNET_CRYPTO_cs_private_key_generate (&priv);
1141 52 : GNUNET_CRYPTO_cs_private_key_get_public (&priv,
1142 : &pub);
1143 52 : GNUNET_CRYPTO_hash (&pub,
1144 : sizeof (pub),
1145 : &dk->h_cs.hash);
1146 52 : GNUNET_asprintf (
1147 : &dk->filename,
1148 : "%s/%s/%llu-%llu",
1149 : keydir,
1150 : denom->section,
1151 52 : (unsigned long long) (dk->anchor_start.abs_time.abs_value_us
1152 52 : / GNUNET_TIME_UNIT_SECONDS.rel_value_us
1153 : ),
1154 52 : (unsigned long long) (dk->anchor_end.abs_time.abs_value_us
1155 52 : / GNUNET_TIME_UNIT_SECONDS.rel_value_us
1156 : ));
1157 52 : if (GNUNET_OK !=
1158 52 : GNUNET_DISK_fn_write (dk->filename,
1159 : &priv,
1160 : sizeof(priv),
1161 : GNUNET_DISK_PERM_USER_READ))
1162 : {
1163 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1164 : "write",
1165 : dk->filename);
1166 0 : return GNUNET_SYSERR;
1167 : }
1168 52 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1169 : "Setup fresh private key %s at %s in `%s' (generation #%llu)\n",
1170 : GNUNET_h2s (&dk->h_cs.hash),
1171 : GNUNET_TIME_timestamp2s (dk->anchor_start),
1172 : dk->filename,
1173 : (unsigned long long) key_gen);
1174 52 : dk->denom_priv = priv;
1175 52 : dk->denom_pub = pub;
1176 52 : dk->key_gen = key_gen;
1177 52 : generate_response (dk);
1178 52 : if (GNUNET_OK !=
1179 52 : GNUNET_CONTAINER_multihashmap_put (
1180 : keys,
1181 52 : &dk->h_cs.hash,
1182 : dk,
1183 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1184 : {
1185 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1186 : "Duplicate private key created! Terminating.\n");
1187 0 : GNUNET_free (dk->filename);
1188 0 : GNUNET_free (dk->an);
1189 0 : GNUNET_free (dk);
1190 0 : return GNUNET_SYSERR;
1191 : }
1192 52 : GNUNET_CONTAINER_DLL_insert_after (denom->keys_head,
1193 : denom->keys_tail,
1194 : position,
1195 : dk);
1196 52 : return GNUNET_OK;
1197 : }
1198 :
1199 :
1200 : /**
1201 : * The withdraw period of a key @a dk has expired. Purge it.
1202 : *
1203 : * @param[in] dk expired denomination key to purge
1204 : */
1205 : static void
1206 3 : purge_key (struct DenominationKey *dk)
1207 : {
1208 3 : if (dk->purge)
1209 0 : return;
1210 3 : if (0 != unlink (dk->filename))
1211 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1212 : "unlink",
1213 : dk->filename);
1214 3 : GNUNET_free (dk->filename);
1215 3 : dk->purge = true;
1216 3 : dk->key_gen = key_gen;
1217 : }
1218 :
1219 :
1220 : /**
1221 : * A @a client informs us that a key has been revoked.
1222 : * Check if the key is still in use, and if so replace (!)
1223 : * it with a fresh key.
1224 : *
1225 : * @param client the client making the request
1226 : * @param rr the revocation request
1227 : */
1228 : static enum GNUNET_GenericReturnValue
1229 3 : handle_revoke_request (struct TES_Client *client,
1230 : const struct TALER_CRYPTO_CsRevokeRequest *rr)
1231 : {
1232 : struct DenominationKey *dk;
1233 : struct DenominationKey *ndk;
1234 : struct Denomination *denom;
1235 :
1236 : (void) client;
1237 3 : GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
1238 3 : dk = GNUNET_CONTAINER_multihashmap_get (keys,
1239 : &rr->h_cs.hash);
1240 3 : if (NULL == dk)
1241 : {
1242 0 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
1243 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1244 : "Revocation request ignored, denomination key %s unknown\n",
1245 : GNUNET_h2s (&rr->h_cs.hash));
1246 0 : return GNUNET_OK;
1247 : }
1248 3 : if (dk->purge)
1249 : {
1250 0 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
1251 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1252 : "Revocation request ignored, denomination key %s already revoked\n",
1253 : GNUNET_h2s (&rr->h_cs.hash));
1254 0 : return GNUNET_OK;
1255 : }
1256 :
1257 3 : key_gen++;
1258 3 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1259 : "Revoking key %s, bumping generation to %llu\n",
1260 : GNUNET_h2s (&rr->h_cs.hash),
1261 : (unsigned long long) key_gen);
1262 3 : purge_key (dk);
1263 :
1264 : /* Setup replacement key */
1265 3 : denom = dk->denom;
1266 3 : ndk = GNUNET_new (struct DenominationKey);
1267 3 : ndk->denom = denom;
1268 3 : ndk->anchor_start = dk->anchor_start;
1269 3 : ndk->anchor_end = dk->anchor_end;
1270 3 : if (GNUNET_OK !=
1271 3 : setup_key (ndk,
1272 : dk))
1273 : {
1274 0 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
1275 0 : GNUNET_break (0);
1276 0 : GNUNET_SCHEDULER_shutdown ();
1277 0 : globals->global_ret = EXIT_FAILURE;
1278 0 : return GNUNET_SYSERR;
1279 : }
1280 3 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
1281 3 : TES_wake_clients ();
1282 3 : return GNUNET_OK;
1283 : }
1284 :
1285 :
1286 : /**
1287 : * Handle @a client request @a rdr to create signature. Create the
1288 : * signature using the respective key and return the result to
1289 : * the client.
1290 : *
1291 : * @param client the client making the request
1292 : * @param rdr the request details
1293 : * @return #GNUNET_OK on success
1294 : */
1295 : static enum GNUNET_GenericReturnValue
1296 0 : handle_r_derive_request (struct TES_Client *client,
1297 : const struct TALER_CRYPTO_CsRDeriveRequest *rdr)
1298 : {
1299 : struct GNUNET_CRYPTO_CSPublicRPairP r_pub;
1300 0 : struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1301 : enum TALER_ErrorCode ec;
1302 : enum GNUNET_GenericReturnValue ret;
1303 :
1304 0 : ec = do_derive (&rdr->h_cs,
1305 : &rdr->nonce,
1306 0 : (0 != ntohl (rdr->for_melt)),
1307 : &r_pub);
1308 0 : if (TALER_EC_NONE != ec)
1309 : {
1310 0 : return fail_derive (client,
1311 : ec);
1312 : }
1313 :
1314 0 : ret = send_derivation (client,
1315 : &r_pub);
1316 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1317 : "Sent CS Derived R after %s\n",
1318 : GNUNET_TIME_relative2s (
1319 : GNUNET_TIME_absolute_get_duration (now),
1320 : GNUNET_YES));
1321 0 : return ret;
1322 : }
1323 :
1324 :
1325 : /**
1326 : * Handle @a hdr message received from @a client.
1327 : *
1328 : * @param client the client that received the message
1329 : * @param hdr message that was received
1330 : * @return #GNUNET_OK on success
1331 : */
1332 : static enum GNUNET_GenericReturnValue
1333 1112 : cs_work_dispatch (struct TES_Client *client,
1334 : const struct GNUNET_MessageHeader *hdr)
1335 : {
1336 1112 : uint16_t msize = ntohs (hdr->size);
1337 :
1338 1112 : switch (ntohs (hdr->type))
1339 : {
1340 0 : case TALER_HELPER_CS_MT_REQ_SIGN:
1341 0 : if (msize < sizeof (struct TALER_CRYPTO_CsSignRequestMessage))
1342 : {
1343 0 : GNUNET_break_op (0);
1344 0 : return GNUNET_SYSERR;
1345 : }
1346 0 : return handle_sign_request (
1347 : client,
1348 : (const struct TALER_CRYPTO_CsSignRequestMessage *) hdr);
1349 3 : case TALER_HELPER_CS_MT_REQ_REVOKE:
1350 3 : if (msize != sizeof (struct TALER_CRYPTO_CsRevokeRequest))
1351 : {
1352 0 : GNUNET_break_op (0);
1353 0 : return GNUNET_SYSERR;
1354 : }
1355 3 : return handle_revoke_request (
1356 : client,
1357 : (const struct TALER_CRYPTO_CsRevokeRequest *) hdr);
1358 951 : case TALER_HELPER_CS_MT_REQ_BATCH_SIGN:
1359 951 : if (msize <= sizeof (struct TALER_CRYPTO_BatchSignRequest))
1360 : {
1361 0 : GNUNET_break_op (0);
1362 0 : return GNUNET_SYSERR;
1363 : }
1364 951 : return handle_batch_sign_request (
1365 : client,
1366 : (const struct TALER_CRYPTO_BatchSignRequest *) hdr);
1367 157 : case TALER_HELPER_CS_MT_REQ_BATCH_RDERIVE:
1368 157 : if (msize <= sizeof (struct TALER_CRYPTO_BatchDeriveRequest))
1369 : {
1370 0 : GNUNET_break_op (0);
1371 0 : return GNUNET_SYSERR;
1372 : }
1373 157 : return handle_batch_derive_request (
1374 : client,
1375 : (const struct TALER_CRYPTO_BatchDeriveRequest *) hdr);
1376 0 : case TALER_HELPER_CS_MT_REQ_RDERIVE:
1377 0 : if (msize != sizeof (struct TALER_CRYPTO_CsRDeriveRequest))
1378 : {
1379 0 : GNUNET_break_op (0);
1380 0 : return GNUNET_SYSERR;
1381 : }
1382 0 : return handle_r_derive_request (client,
1383 : (const struct
1384 : TALER_CRYPTO_CsRDeriveRequest *) hdr);
1385 1 : default:
1386 1 : GNUNET_break_op (0);
1387 0 : return GNUNET_SYSERR;
1388 : }
1389 : }
1390 :
1391 :
1392 : /**
1393 : * Send our initial key set to @a client together with the
1394 : * "sync" terminator.
1395 : *
1396 : * @param client the client to inform
1397 : * @return #GNUNET_OK on success
1398 : */
1399 : static enum GNUNET_GenericReturnValue
1400 30 : cs_client_init (struct TES_Client *client)
1401 : {
1402 30 : size_t obs = 0;
1403 : char *buf;
1404 :
1405 30 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1406 : "Initializing new client %p\n",
1407 : client);
1408 30 : GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
1409 30 : for (struct Denomination *denom = denom_head;
1410 95 : NULL != denom;
1411 65 : denom = denom->next)
1412 : {
1413 65 : for (struct DenominationKey *dk = denom->keys_head;
1414 304 : NULL != dk;
1415 239 : dk = dk->next)
1416 : {
1417 239 : obs += ntohs (dk->an->header.size);
1418 : }
1419 : }
1420 30 : buf = GNUNET_malloc (obs);
1421 30 : obs = 0;
1422 30 : for (struct Denomination *denom = denom_head;
1423 95 : NULL != denom;
1424 65 : denom = denom->next)
1425 : {
1426 65 : for (struct DenominationKey *dk = denom->keys_head;
1427 304 : NULL != dk;
1428 239 : dk = dk->next)
1429 : {
1430 239 : GNUNET_memcpy (&buf[obs],
1431 : dk->an,
1432 : ntohs (dk->an->header.size));
1433 239 : obs += ntohs (dk->an->header.size);
1434 : }
1435 : }
1436 30 : client->key_gen = key_gen;
1437 30 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
1438 30 : if (GNUNET_OK !=
1439 30 : TES_transmit_raw (client->csock,
1440 : obs,
1441 : buf))
1442 : {
1443 0 : GNUNET_free (buf);
1444 0 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1445 : "Client %p must have disconnected\n",
1446 : client);
1447 0 : return GNUNET_SYSERR;
1448 : }
1449 30 : GNUNET_free (buf);
1450 : {
1451 30 : struct GNUNET_MessageHeader synced = {
1452 30 : .type = htons (TALER_HELPER_CS_SYNCED),
1453 30 : .size = htons (sizeof (synced))
1454 : };
1455 :
1456 30 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1457 : "Sending CS SYNCED message to %p\n",
1458 : client);
1459 30 : if (GNUNET_OK !=
1460 30 : TES_transmit (client->csock,
1461 : &synced))
1462 : {
1463 0 : GNUNET_break (0);
1464 0 : return GNUNET_SYSERR;
1465 : }
1466 : }
1467 30 : return GNUNET_OK;
1468 : }
1469 :
1470 :
1471 : /**
1472 : * Notify @a client about all changes to the keys since
1473 : * the last generation known to the @a client.
1474 : *
1475 : * @param client the client to notify
1476 : * @return #GNUNET_OK on success
1477 : */
1478 : static enum GNUNET_GenericReturnValue
1479 23 : cs_update_client_keys (struct TES_Client *client)
1480 : {
1481 23 : size_t obs = 0;
1482 : char *buf;
1483 : enum GNUNET_GenericReturnValue ret;
1484 :
1485 23 : GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
1486 23 : for (struct Denomination *denom = denom_head;
1487 81 : NULL != denom;
1488 58 : denom = denom->next)
1489 : {
1490 58 : for (struct DenominationKey *key = denom->keys_head;
1491 254 : NULL != key;
1492 196 : key = key->next)
1493 : {
1494 196 : if (key->key_gen <= client->key_gen)
1495 187 : continue;
1496 9 : if (key->purge)
1497 3 : obs += sizeof (struct TALER_CRYPTO_CsKeyPurgeNotification);
1498 : else
1499 6 : obs += ntohs (key->an->header.size);
1500 : }
1501 : }
1502 23 : if (0 == obs)
1503 : {
1504 : /* nothing to do */
1505 17 : client->key_gen = key_gen;
1506 17 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
1507 17 : return GNUNET_OK;
1508 : }
1509 6 : buf = GNUNET_malloc (obs);
1510 6 : obs = 0;
1511 6 : for (struct Denomination *denom = denom_head;
1512 12 : NULL != denom;
1513 6 : denom = denom->next)
1514 : {
1515 6 : for (struct DenominationKey *key = denom->keys_head;
1516 42 : NULL != key;
1517 36 : key = key->next)
1518 : {
1519 36 : if (key->key_gen <= client->key_gen)
1520 27 : continue;
1521 9 : if (key->purge)
1522 : {
1523 3 : struct TALER_CRYPTO_CsKeyPurgeNotification pn = {
1524 3 : .header.type = htons (TALER_HELPER_CS_MT_PURGE),
1525 3 : .header.size = htons (sizeof (pn)),
1526 : .h_cs = key->h_cs
1527 : };
1528 :
1529 3 : GNUNET_memcpy (&buf[obs],
1530 : &pn,
1531 : sizeof (pn));
1532 3 : GNUNET_assert (obs + sizeof (pn)
1533 : > obs);
1534 3 : obs += sizeof (pn);
1535 : }
1536 : else
1537 : {
1538 6 : GNUNET_memcpy (&buf[obs],
1539 : key->an,
1540 : ntohs (key->an->header.size));
1541 6 : GNUNET_assert (obs + ntohs (key->an->header.size)
1542 : > obs);
1543 6 : obs += ntohs (key->an->header.size);
1544 : }
1545 : }
1546 : }
1547 6 : client->key_gen = key_gen;
1548 6 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
1549 6 : ret = TES_transmit_raw (client->csock,
1550 : obs,
1551 : buf);
1552 6 : GNUNET_free (buf);
1553 6 : return ret;
1554 : }
1555 :
1556 :
1557 : /**
1558 : * Create a new denomination key (we do not have enough).
1559 : *
1560 : * @param[in,out] denom denomination key to create
1561 : * @param anchor_start when to start key signing validity
1562 : * @param anchor_end when to end key signing validity
1563 : * @return #GNUNET_OK on success
1564 : */
1565 : static enum GNUNET_GenericReturnValue
1566 49 : create_key (struct Denomination *denom,
1567 : struct GNUNET_TIME_Timestamp anchor_start,
1568 : struct GNUNET_TIME_Timestamp anchor_end)
1569 : {
1570 : struct DenominationKey *dk;
1571 :
1572 49 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1573 : "Creating new key for `%s' with start date %s\n",
1574 : denom->section,
1575 : GNUNET_TIME_timestamp2s (anchor_start));
1576 49 : dk = GNUNET_new (struct DenominationKey);
1577 49 : dk->denom = denom;
1578 49 : dk->anchor_start = anchor_start;
1579 49 : dk->anchor_end = anchor_end;
1580 49 : if (GNUNET_OK !=
1581 49 : setup_key (dk,
1582 : denom->keys_tail))
1583 : {
1584 0 : GNUNET_break (0);
1585 0 : GNUNET_free (dk);
1586 0 : GNUNET_SCHEDULER_shutdown ();
1587 0 : globals->global_ret = EXIT_FAILURE;
1588 0 : return GNUNET_SYSERR;
1589 : }
1590 49 : return GNUNET_OK;
1591 : }
1592 :
1593 :
1594 : /**
1595 : * Obtain the maximum withdraw duration of all denominations.
1596 : *
1597 : * Must only be called while the #keys_lock is held.
1598 : *
1599 : * @return maximum withdraw duration, zero if there are no denominations
1600 : */
1601 : static struct GNUNET_TIME_Relative
1602 52 : get_maximum_duration (void)
1603 : {
1604 52 : struct GNUNET_TIME_Relative ret
1605 : = GNUNET_TIME_UNIT_ZERO;
1606 :
1607 52 : for (struct Denomination *denom = denom_head;
1608 229 : NULL != denom;
1609 177 : denom = denom->next)
1610 : {
1611 177 : ret = GNUNET_TIME_relative_max (ret,
1612 : denom->duration_withdraw);
1613 : }
1614 52 : return ret;
1615 : }
1616 :
1617 :
1618 : /**
1619 : * At what time do we need to next create keys if we just did?
1620 : *
1621 : * @return time when to next create keys if we just finished key generation
1622 : */
1623 : static struct GNUNET_TIME_Absolute
1624 15 : action_time (void)
1625 : {
1626 15 : struct GNUNET_TIME_Relative md = get_maximum_duration ();
1627 15 : struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1628 : uint64_t mod;
1629 :
1630 15 : if (GNUNET_TIME_relative_is_zero (md))
1631 0 : return GNUNET_TIME_UNIT_FOREVER_ABS;
1632 15 : mod = now.abs_value_us % md.rel_value_us;
1633 15 : now.abs_value_us -= mod;
1634 15 : return GNUNET_TIME_absolute_add (now,
1635 : md);
1636 : }
1637 :
1638 :
1639 : /**
1640 : * Remove all denomination keys of @a denom that have expired.
1641 : *
1642 : * @param[in,out] denom denomination family to remove keys for
1643 : */
1644 : static void
1645 234 : remove_expired_denomination_keys (struct Denomination *denom)
1646 : {
1647 466 : while ( (NULL != denom->keys_head) &&
1648 226 : GNUNET_TIME_absolute_is_past (
1649 226 : denom->keys_head->anchor_end.abs_time) )
1650 : {
1651 6 : struct DenominationKey *key = denom->keys_head;
1652 6 : struct DenominationKey *nxt = key->next;
1653 :
1654 6 : if (0 != key->rc)
1655 0 : break; /* later */
1656 6 : GNUNET_CONTAINER_DLL_remove (denom->keys_head,
1657 : denom->keys_tail,
1658 : key);
1659 6 : GNUNET_assert (GNUNET_OK ==
1660 : GNUNET_CONTAINER_multihashmap_remove (
1661 : keys,
1662 : &key->h_cs.hash,
1663 : key));
1664 12 : if ( (! key->purge) &&
1665 6 : (0 != unlink (key->filename)) )
1666 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1667 : "unlink",
1668 : key->filename);
1669 6 : GNUNET_free (key->filename);
1670 6 : GNUNET_free (key->an);
1671 6 : GNUNET_free (key);
1672 6 : key = nxt;
1673 : }
1674 234 : }
1675 :
1676 :
1677 : /**
1678 : * Obtain the end anchor to use at this point. Uses the
1679 : * #lookahead_sign and then rounds it up by the maximum
1680 : * duration of any denomination to arrive at a globally
1681 : * valid end-date.
1682 : *
1683 : * Must only be called while the #keys_lock is held.
1684 : *
1685 : * @return end anchor
1686 : */
1687 : static struct GNUNET_TIME_Timestamp
1688 37 : get_anchor_end (void)
1689 : {
1690 37 : struct GNUNET_TIME_Relative md = get_maximum_duration ();
1691 : struct GNUNET_TIME_Absolute end
1692 37 : = GNUNET_TIME_relative_to_absolute (lookahead_sign);
1693 : uint64_t mod;
1694 :
1695 37 : if (GNUNET_TIME_relative_is_zero (md))
1696 10 : return GNUNET_TIME_UNIT_ZERO_TS;
1697 : /* Round up 'end' to a multiple of 'md' */
1698 27 : mod = end.abs_value_us % md.rel_value_us;
1699 27 : end.abs_value_us -= mod;
1700 27 : return GNUNET_TIME_absolute_to_timestamp (
1701 : GNUNET_TIME_absolute_add (end,
1702 : md));
1703 : }
1704 :
1705 :
1706 : /**
1707 : * Create all denomination keys that are required for our
1708 : * desired lookahead and that we do not yet have.
1709 : *
1710 : * @param[in,out] opt our options
1711 : * @param[in,out] wake set to true if we should wake the clients
1712 : */
1713 : static void
1714 37 : create_missing_keys (struct TALER_SECMOD_Options *opt,
1715 : bool *wake)
1716 : {
1717 : struct GNUNET_TIME_Timestamp start;
1718 : struct GNUNET_TIME_Timestamp end;
1719 :
1720 37 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1721 : "Updating denominations ...\n");
1722 37 : start = opt->global_now;
1723 37 : GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
1724 37 : end = get_anchor_end ();
1725 37 : for (struct Denomination *denom = denom_head;
1726 154 : NULL != denom;
1727 117 : denom = denom->next)
1728 : {
1729 : struct GNUNET_TIME_Timestamp anchor_start;
1730 : struct GNUNET_TIME_Timestamp anchor_end;
1731 : struct GNUNET_TIME_Timestamp next_end;
1732 117 : bool finished = false;
1733 :
1734 117 : remove_expired_denomination_keys (denom);
1735 117 : if (NULL != denom->keys_tail)
1736 : {
1737 103 : anchor_start = denom->keys_tail->anchor_end;
1738 103 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1739 : "Expanding keys of denomination `%s', last key %s valid for another %s\n",
1740 : denom->section,
1741 : GNUNET_h2s (&denom->keys_tail->h_cs.hash),
1742 : GNUNET_TIME_relative2s (
1743 : GNUNET_TIME_absolute_get_remaining (
1744 : anchor_start.abs_time),
1745 : true));
1746 : }
1747 : else
1748 : {
1749 14 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1750 : "Starting keys of denomination `%s'\n",
1751 : denom->section);
1752 : /* Round the very first anchor down to the configured calendar
1753 : interval; subsequent anchors inherit the alignment from the
1754 : (rounded up) end of the preceding key. The UTC variants are used
1755 : so that the result does not depend on the time zone the secmod
1756 : happens to run in. */
1757 14 : anchor_start = GNUNET_TIME_absolute_to_timestamp (
1758 : GNUNET_TIME_round_down_utc (start.abs_time,
1759 : denom->anchor_round));
1760 : }
1761 117 : finished = GNUNET_TIME_timestamp_cmp (anchor_start,
1762 : >=,
1763 : end);
1764 166 : while (! finished)
1765 : {
1766 : /* Round the end of the validity period up to the configured calendar
1767 : interval. As #GNUNET_TIME_UNIT_YEARS is 365 days, this is also what
1768 : keeps the anchors from drifting off the calendar boundary across leap
1769 : years. Without ANCHOR_ROUND, all of this is a no-op. */
1770 49 : anchor_end = GNUNET_TIME_absolute_to_timestamp (
1771 : GNUNET_TIME_round_up_utc (
1772 : GNUNET_TIME_absolute_add (anchor_start.abs_time,
1773 : denom->duration_withdraw),
1774 : denom->anchor_round));
1775 49 : next_end = GNUNET_TIME_absolute_to_timestamp (
1776 : GNUNET_TIME_round_up_utc (
1777 : GNUNET_TIME_absolute_add (anchor_end.abs_time,
1778 : denom->duration_withdraw),
1779 : denom->anchor_round));
1780 49 : if (GNUNET_TIME_timestamp_cmp (next_end,
1781 : >,
1782 : end))
1783 : {
1784 : /* With ANCHOR_ROUND set the calendar interval already provides the
1785 : alignment, and stretching the last key would make it cover more
1786 : than the one interval it is supposed to cover. */
1787 17 : if (GNUNET_TIME_RI_NONE == denom->anchor_round)
1788 16 : anchor_end = end; /* extend period to align end periods */
1789 17 : finished = true;
1790 : }
1791 : /* adjust start time down to ensure overlap */
1792 49 : anchor_start = GNUNET_TIME_absolute_to_timestamp (
1793 : GNUNET_TIME_absolute_subtract (anchor_start.abs_time,
1794 : overlap_duration));
1795 49 : if (! *wake)
1796 : {
1797 3 : key_gen++;
1798 3 : *wake = true;
1799 : }
1800 49 : if (GNUNET_OK !=
1801 49 : create_key (denom,
1802 : anchor_start,
1803 : anchor_end))
1804 : {
1805 0 : GNUNET_break (0);
1806 0 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
1807 0 : globals->global_ret = EXIT_FAILURE;
1808 0 : GNUNET_SCHEDULER_shutdown ();
1809 0 : return;
1810 : }
1811 49 : anchor_start = anchor_end;
1812 : }
1813 117 : remove_expired_denomination_keys (denom);
1814 : }
1815 37 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
1816 37 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1817 : "Updating denominations finished ...\n");
1818 : }
1819 :
1820 :
1821 : /**
1822 : * Task run periodically to expire keys and/or generate fresh ones.
1823 : *
1824 : * @param cls the `struct TALER_SECMOD_Options *`
1825 : */
1826 : static void
1827 15 : update_denominations (void *cls)
1828 : {
1829 15 : struct TALER_SECMOD_Options *opt = cls;
1830 : struct GNUNET_TIME_Absolute at;
1831 15 : bool wake = false;
1832 :
1833 : (void) cls;
1834 15 : keygen_task = NULL;
1835 15 : opt->global_now = GNUNET_TIME_timestamp_get ();
1836 15 : create_missing_keys (opt,
1837 : &wake);
1838 15 : if (wake)
1839 3 : TES_wake_clients ();
1840 15 : at = action_time ();
1841 15 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1842 : "Next key generation due at %s\n",
1843 : GNUNET_TIME_absolute2s (at));
1844 15 : keygen_task = GNUNET_SCHEDULER_add_at (at,
1845 : &update_denominations,
1846 : opt);
1847 15 : }
1848 :
1849 :
1850 : /**
1851 : * Parse private key of denomination @a denom in @a buf.
1852 : *
1853 : * @param[out] denom denomination of the key
1854 : * @param filename name of the file we are parsing, for logging
1855 : * @param priv key material
1856 : */
1857 : static void
1858 134 : parse_key (struct Denomination *denom,
1859 : const char *filename,
1860 : const struct GNUNET_CRYPTO_CsPrivateKey *priv)
1861 : {
1862 : const char *anchor_s;
1863 : char dummy;
1864 : unsigned long long anchor_start_ll;
1865 : unsigned long long anchor_end_ll;
1866 : struct GNUNET_TIME_Timestamp anchor_start;
1867 : struct GNUNET_TIME_Timestamp anchor_end;
1868 134 : char *nf = NULL;
1869 :
1870 134 : anchor_s = strrchr (filename,
1871 : '/');
1872 134 : if (NULL == anchor_s)
1873 : {
1874 : /* File in a directory without '/' in the name, this makes no sense. */
1875 0 : GNUNET_break (0);
1876 0 : return;
1877 : }
1878 134 : anchor_s++;
1879 134 : if (2 != sscanf (anchor_s,
1880 : "%llu-%llu%c",
1881 : &anchor_start_ll,
1882 : &anchor_end_ll,
1883 : &dummy))
1884 : {
1885 : /* try legacy mode */
1886 3 : if (1 != sscanf (anchor_s,
1887 : "%llu%c",
1888 : &anchor_start_ll,
1889 : &dummy))
1890 : {
1891 : /* Filenames in KEYDIR must ONLY be the anchor time in seconds! */
1892 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1893 : "Filename `%s' invalid for key file, skipping\n",
1894 : anchor_s);
1895 0 : return;
1896 : }
1897 : anchor_start.abs_time.abs_value_us
1898 3 : = anchor_start_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us;
1899 6 : if (anchor_start_ll != anchor_start.abs_time.abs_value_us
1900 3 : / GNUNET_TIME_UNIT_SECONDS.rel_value_us)
1901 : {
1902 : /* Integer overflow. Bad, invalid filename. */
1903 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1904 : "Integer overflow. Filename `%s' invalid for key file, skipping\n",
1905 : anchor_s);
1906 0 : return;
1907 : }
1908 : anchor_end
1909 3 : = GNUNET_TIME_absolute_to_timestamp (
1910 : GNUNET_TIME_absolute_add (anchor_start.abs_time,
1911 : denom->duration_withdraw));
1912 3 : GNUNET_asprintf (
1913 : &nf,
1914 : "%s/%s/%llu-%llu",
1915 : keydir,
1916 : denom->section,
1917 : anchor_start_ll,
1918 3 : (unsigned long long) (anchor_end.abs_time.abs_value_us
1919 3 : / GNUNET_TIME_UNIT_SECONDS.rel_value_us));
1920 : /* Try to fix the legacy filename */
1921 3 : if (0 !=
1922 3 : rename (filename,
1923 : nf))
1924 : {
1925 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
1926 : "rename",
1927 : filename);
1928 0 : GNUNET_free (nf);
1929 : }
1930 : }
1931 : else
1932 : {
1933 : anchor_start.abs_time.abs_value_us
1934 131 : = anchor_start_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us;
1935 : anchor_end.abs_time.abs_value_us
1936 131 : = anchor_end_ll * GNUNET_TIME_UNIT_SECONDS.rel_value_us;
1937 262 : if ( (anchor_start_ll != anchor_start.abs_time.abs_value_us
1938 131 : / GNUNET_TIME_UNIT_SECONDS.rel_value_us) ||
1939 262 : (anchor_end_ll != anchor_end.abs_time.abs_value_us
1940 131 : / GNUNET_TIME_UNIT_SECONDS.rel_value_us) )
1941 : {
1942 : /* Integer overflow. Bad, invalid filename. */
1943 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1944 : "Integer overflow. Filename `%s' invalid for key file, skipping\n",
1945 : anchor_s);
1946 0 : return;
1947 : }
1948 : }
1949 :
1950 : {
1951 : struct DenominationKey *dk;
1952 : struct DenominationKey *before;
1953 :
1954 134 : dk = GNUNET_new (struct DenominationKey);
1955 134 : dk->denom_priv = *priv;
1956 134 : dk->denom = denom;
1957 134 : dk->anchor_start = anchor_start;
1958 134 : dk->anchor_end = anchor_end;
1959 134 : dk->filename = (NULL == nf) ? GNUNET_strdup (filename) : nf;
1960 134 : GNUNET_CRYPTO_cs_private_key_get_public (priv,
1961 : &dk->denom_pub);
1962 134 : GNUNET_CRYPTO_hash (&dk->denom_pub,
1963 : sizeof (dk->denom_pub),
1964 : &dk->h_cs.hash);
1965 134 : generate_response (dk);
1966 134 : if (GNUNET_OK !=
1967 134 : GNUNET_CONTAINER_multihashmap_put (
1968 : keys,
1969 134 : &dk->h_cs.hash,
1970 : dk,
1971 : GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1972 : {
1973 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1974 : "Duplicate private key %s detected in file `%s'. Skipping.\n",
1975 : GNUNET_h2s (&dk->h_cs.hash),
1976 : filename);
1977 0 : GNUNET_free (dk->an);
1978 0 : GNUNET_free (dk);
1979 0 : return;
1980 : }
1981 134 : before = NULL;
1982 134 : for (struct DenominationKey *pos = denom->keys_head;
1983 135 : NULL != pos;
1984 1 : pos = pos->next)
1985 : {
1986 90 : if (GNUNET_TIME_timestamp_cmp (pos->anchor_start,
1987 : >,
1988 : anchor_start))
1989 89 : break;
1990 1 : before = pos;
1991 : }
1992 134 : GNUNET_CONTAINER_DLL_insert_after (denom->keys_head,
1993 : denom->keys_tail,
1994 : before,
1995 : dk);
1996 134 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1997 : "Imported key %s from `%s'\n",
1998 : GNUNET_h2s (&dk->h_cs.hash),
1999 : filename);
2000 : }
2001 : }
2002 :
2003 :
2004 : /**
2005 : * Import a private key from @a filename for the denomination
2006 : * given in @a cls.
2007 : *
2008 : * @param[in,out] cls a `struct Denomiantion`
2009 : * @param filename name of a file in the directory
2010 : * @return #GNUNET_OK (always, continue to iterate)
2011 : */
2012 : static enum GNUNET_GenericReturnValue
2013 134 : import_key (void *cls,
2014 : const char *filename)
2015 : {
2016 134 : struct Denomination *denom = cls;
2017 : struct GNUNET_DISK_FileHandle *fh;
2018 : struct GNUNET_DISK_MapHandle *map;
2019 : void *ptr;
2020 : int fd;
2021 : struct stat sbuf;
2022 :
2023 : {
2024 : struct stat lsbuf;
2025 :
2026 134 : if (0 != lstat (filename,
2027 : &lsbuf))
2028 : {
2029 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
2030 : "lstat",
2031 : filename);
2032 0 : return GNUNET_OK;
2033 : }
2034 134 : if (! S_ISREG (lsbuf.st_mode))
2035 : {
2036 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2037 : "File `%s' is not a regular file, which is not allowed for private keys!\n",
2038 : filename);
2039 0 : return GNUNET_OK;
2040 : }
2041 : }
2042 :
2043 134 : fd = open (filename,
2044 : O_RDONLY | O_CLOEXEC);
2045 134 : if (-1 == fd)
2046 : {
2047 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
2048 : "open",
2049 : filename);
2050 0 : return GNUNET_OK;
2051 : }
2052 134 : if (0 != fstat (fd,
2053 : &sbuf))
2054 : {
2055 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
2056 : "stat",
2057 : filename);
2058 0 : GNUNET_break (0 == close (fd));
2059 0 : return GNUNET_OK;
2060 : }
2061 134 : if (! S_ISREG (sbuf.st_mode))
2062 : {
2063 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2064 : "File `%s' is not a regular file, which is not allowed for private keys!\n",
2065 : filename);
2066 0 : GNUNET_break (0 == close (fd));
2067 0 : return GNUNET_OK;
2068 : }
2069 134 : if (0 != (sbuf.st_mode & (S_IWUSR | S_IRWXG | S_IRWXO)))
2070 : {
2071 : /* permission are NOT tight, try to patch them up! */
2072 0 : if (0 !=
2073 0 : fchmod (fd,
2074 : S_IRUSR))
2075 : {
2076 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
2077 : "fchmod",
2078 : filename);
2079 : /* refuse to use key if file has wrong permissions */
2080 0 : GNUNET_break (0 == close (fd));
2081 0 : return GNUNET_OK;
2082 : }
2083 : }
2084 134 : fh = GNUNET_DISK_get_handle_from_int_fd (fd);
2085 134 : if (NULL == fh)
2086 : {
2087 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
2088 : "open",
2089 : filename);
2090 0 : GNUNET_break (0 == close (fd));
2091 0 : return GNUNET_OK;
2092 : }
2093 134 : if (sbuf.st_size != sizeof(struct GNUNET_CRYPTO_CsPrivateKey))
2094 : {
2095 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2096 : "File `%s' too big to be a private key\n",
2097 : filename);
2098 0 : GNUNET_DISK_file_close (fh);
2099 0 : return GNUNET_OK;
2100 : }
2101 134 : ptr = GNUNET_DISK_file_map (fh,
2102 : &map,
2103 : GNUNET_DISK_MAP_TYPE_READ,
2104 134 : (size_t) sbuf.st_size);
2105 134 : if (NULL == ptr)
2106 : {
2107 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
2108 : "mmap",
2109 : filename);
2110 0 : GNUNET_DISK_file_close (fh);
2111 0 : return GNUNET_OK;
2112 : }
2113 134 : parse_key (denom,
2114 : filename,
2115 : (const struct GNUNET_CRYPTO_CsPrivateKey *) ptr);
2116 134 : GNUNET_DISK_file_unmap (map);
2117 134 : GNUNET_DISK_file_close (fh);
2118 134 : return GNUNET_OK;
2119 : }
2120 :
2121 :
2122 : /**
2123 : * Parse configuration for denomination type parameters. Also determines
2124 : * our anchor by looking at the existing denominations of the same type.
2125 : *
2126 : * @param cfg configuration to use
2127 : * @param ct section in the configuration file giving the denomination type parameters
2128 : * @param[out] denom set to the denomination parameters from the configuration
2129 : * @return #GNUNET_OK on success, #GNUNET_SYSERR if the configuration is invalid
2130 : */
2131 : static enum GNUNET_GenericReturnValue
2132 57 : parse_denomination_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg,
2133 : const char *ct,
2134 : struct Denomination *denom)
2135 : {
2136 : char *secname;
2137 :
2138 57 : GNUNET_asprintf (&secname,
2139 : "%s-secmod-cs",
2140 57 : globals->section);
2141 57 : if (GNUNET_OK !=
2142 57 : GNUNET_CONFIGURATION_get_value_time (cfg,
2143 : ct,
2144 : "DURATION_WITHDRAW",
2145 : &denom->duration_withdraw))
2146 : {
2147 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2148 : ct,
2149 : "DURATION_WITHDRAW");
2150 0 : GNUNET_free (secname);
2151 0 : return GNUNET_SYSERR;
2152 : }
2153 57 : if (GNUNET_TIME_relative_cmp (denom->duration_withdraw,
2154 : <,
2155 : GNUNET_TIME_UNIT_SECONDS))
2156 : {
2157 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2158 : ct,
2159 : "DURATION_WITHDRAW",
2160 : "less than one second is not supported");
2161 0 : GNUNET_free (secname);
2162 0 : return GNUNET_SYSERR;
2163 : }
2164 57 : if (GNUNET_TIME_relative_cmp (overlap_duration,
2165 : >=,
2166 : denom->duration_withdraw))
2167 : {
2168 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2169 : secname,
2170 : "OVERLAP_DURATION",
2171 : "Value given must be smaller than value for DURATION_WITHDRAW!");
2172 0 : GNUNET_free (secname);
2173 0 : return GNUNET_SYSERR;
2174 : }
2175 : {
2176 : struct GNUNET_TIME_Relative ar;
2177 :
2178 : /* The denomination section takes precedence, the secmod section
2179 : provides the default for all denominations. */
2180 57 : if ( (GNUNET_OK !=
2181 57 : GNUNET_CONFIGURATION_get_value_time (cfg,
2182 : ct,
2183 : "ANCHOR_ROUND",
2184 53 : &ar)) &&
2185 : (GNUNET_OK !=
2186 53 : GNUNET_CONFIGURATION_get_value_time (cfg,
2187 : secname,
2188 : "ANCHOR_ROUND",
2189 : &ar)) )
2190 0 : ar = GNUNET_TIME_UNIT_ZERO; /* not configured: do not round */
2191 : denom->anchor_round
2192 57 : = GNUNET_TIME_relative_to_round_interval (ar);
2193 57 : if ( (GNUNET_TIME_RI_NONE == denom->anchor_round) &&
2194 53 : (! GNUNET_TIME_relative_is_zero (ar)) )
2195 : {
2196 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
2197 : ct,
2198 : "ANCHOR_ROUND",
2199 : "Value given must be zero or exactly one second, minute, hour, day, week, month, quarter or year");
2200 0 : GNUNET_free (secname);
2201 0 : return GNUNET_SYSERR;
2202 : }
2203 : }
2204 57 : GNUNET_free (secname);
2205 57 : denom->section = TES_normalize_section (ct);
2206 57 : return GNUNET_OK;
2207 : }
2208 :
2209 :
2210 : /**
2211 : * Closure for #load_denominations.
2212 : */
2213 : struct LoadContext
2214 : {
2215 :
2216 : /**
2217 : * Configuration to use.
2218 : */
2219 : const struct GNUNET_CONFIGURATION_Handle *cfg;
2220 :
2221 : /**
2222 : * Current time to use.
2223 : */
2224 : struct GNUNET_TIME_Timestamp t;
2225 :
2226 : /**
2227 : * Configuration section prefix to use for denomination settings.
2228 : * "coin_" for the exchange, "doco_" for Donau.
2229 : */
2230 : const char *cprefix;
2231 :
2232 : /**
2233 : * Status, to be set to #GNUNET_SYSERR on failure
2234 : */
2235 : enum GNUNET_GenericReturnValue ret;
2236 : };
2237 :
2238 :
2239 : /**
2240 : * Generate new denomination signing keys for the denomination type of the given @a
2241 : * denomination_alias.
2242 : *
2243 : * @param cls a `struct LoadContext`, with 'ret' to be set to #GNUNET_SYSERR on failure
2244 : * @param denomination_alias name of the denomination's section in the configuration
2245 : */
2246 : static void
2247 903 : load_denominations (void *cls,
2248 : const char *denomination_alias)
2249 : {
2250 903 : struct LoadContext *ctx = cls;
2251 : struct Denomination *denom;
2252 : char *cipher;
2253 :
2254 903 : if (0 != strncasecmp (denomination_alias,
2255 : ctx->cprefix,
2256 : strlen (ctx->cprefix)))
2257 846 : return; /* not a denomination type definition */
2258 121 : if (GNUNET_OK !=
2259 121 : GNUNET_CONFIGURATION_get_value_string (ctx->cfg,
2260 : denomination_alias,
2261 : "CIPHER",
2262 : &cipher))
2263 : {
2264 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2265 : denomination_alias,
2266 : "CIPHER");
2267 0 : return;
2268 : }
2269 121 : if (0 != strcmp (cipher, "CS"))
2270 : {
2271 64 : GNUNET_free (cipher);
2272 64 : return; /* Ignore denominations of other types than CS*/
2273 : }
2274 57 : GNUNET_free (cipher);
2275 :
2276 57 : denom = GNUNET_new (struct Denomination);
2277 57 : if (GNUNET_OK !=
2278 57 : parse_denomination_cfg (ctx->cfg,
2279 : denomination_alias,
2280 : denom))
2281 : {
2282 0 : ctx->ret = GNUNET_SYSERR;
2283 0 : GNUNET_free (denom);
2284 0 : return;
2285 : }
2286 57 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2287 : "Loading keys for denomination %s\n",
2288 : denom->section);
2289 : {
2290 : char *dname;
2291 :
2292 57 : GNUNET_asprintf (&dname,
2293 : "%s/%s",
2294 : keydir,
2295 : denom->section);
2296 57 : GNUNET_break (GNUNET_OK ==
2297 : GNUNET_DISK_directory_create (dname));
2298 57 : GNUNET_DISK_directory_scan (dname,
2299 : &import_key,
2300 : denom);
2301 57 : GNUNET_free (dname);
2302 : }
2303 57 : GNUNET_CONTAINER_DLL_insert (denom_head,
2304 : denom_tail,
2305 : denom);
2306 : }
2307 :
2308 :
2309 : /**
2310 : * Load the various duration values from @a cfg
2311 : *
2312 : * @param cfg configuration to use
2313 : * @return #GNUNET_OK on success
2314 : */
2315 : static enum GNUNET_GenericReturnValue
2316 35 : load_durations (const struct GNUNET_CONFIGURATION_Handle *cfg)
2317 : {
2318 : char *secname;
2319 :
2320 35 : GNUNET_asprintf (&secname,
2321 : "%s-secmod-cs",
2322 35 : globals->section);
2323 35 : if (GNUNET_OK !=
2324 35 : GNUNET_CONFIGURATION_get_value_time (cfg,
2325 : secname,
2326 : "OVERLAP_DURATION",
2327 : &overlap_duration))
2328 : {
2329 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2330 : secname,
2331 : "OVERLAP_DURATION");
2332 0 : GNUNET_free (secname);
2333 0 : return GNUNET_SYSERR;
2334 : }
2335 35 : if (GNUNET_OK !=
2336 35 : GNUNET_CONFIGURATION_get_value_time (cfg,
2337 : secname,
2338 : "LOOKAHEAD_SIGN",
2339 : &lookahead_sign))
2340 : {
2341 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2342 : secname,
2343 : "LOOKAHEAD_SIGN");
2344 0 : GNUNET_free (secname);
2345 0 : return GNUNET_SYSERR;
2346 : }
2347 35 : GNUNET_free (secname);
2348 35 : return GNUNET_OK;
2349 : }
2350 :
2351 :
2352 : /**
2353 : * Function run on shutdown. Stops the various jobs (nicely).
2354 : *
2355 : * @param cls a `struct TALER_SECMOD_Options`
2356 : */
2357 : static void
2358 22 : do_shutdown (void *cls)
2359 : {
2360 : (void) cls;
2361 22 : TES_listen_stop ();
2362 22 : if (NULL != keygen_task)
2363 : {
2364 12 : GNUNET_SCHEDULER_cancel (keygen_task);
2365 12 : keygen_task = NULL;
2366 : }
2367 22 : stop_workers ();
2368 22 : sem_done (&worker_sem);
2369 22 : }
2370 :
2371 :
2372 : void
2373 35 : TALER_SECMOD_cs_run (void *cls,
2374 : char *const *args,
2375 : const char *cfgfile,
2376 : const struct GNUNET_CONFIGURATION_Handle *cfg)
2377 : {
2378 : static struct TES_Callbacks cb = {
2379 : .dispatch = &cs_work_dispatch,
2380 : .updater = &cs_update_client_keys,
2381 : .init = &cs_client_init
2382 : };
2383 35 : struct TALER_SECMOD_Options *opt = cls;
2384 : char *secname;
2385 :
2386 : (void) args;
2387 : (void) cfgfile;
2388 35 : globals = opt;
2389 35 : if (GNUNET_TIME_timestamp_cmp (opt->global_now,
2390 : !=,
2391 : opt->global_now_tmp))
2392 : {
2393 : /* The user gave "--now", use it! */
2394 0 : opt->global_now = opt->global_now_tmp;
2395 : }
2396 : else
2397 : {
2398 : /* get current time again, we may be timetraveling! */
2399 35 : opt->global_now = GNUNET_TIME_timestamp_get ();
2400 : }
2401 35 : GNUNET_asprintf (&secname,
2402 : "%s-secmod-cs",
2403 : opt->section);
2404 35 : if (GNUNET_OK !=
2405 35 : GNUNET_CONFIGURATION_get_value_filename (cfg,
2406 : secname,
2407 : "KEY_DIR",
2408 : &keydir))
2409 : {
2410 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
2411 : secname,
2412 : "KEY_DIR");
2413 0 : GNUNET_free (secname);
2414 0 : opt->global_ret = EXIT_NOTCONFIGURED;
2415 23 : return;
2416 : }
2417 35 : if (GNUNET_OK !=
2418 35 : load_durations (cfg))
2419 : {
2420 0 : opt->global_ret = EXIT_NOTCONFIGURED;
2421 0 : GNUNET_free (secname);
2422 0 : return;
2423 : }
2424 35 : if (GNUNET_OK !=
2425 35 : TES_normalize_key_directory (cfg,
2426 : keydir,
2427 : opt->cprefix))
2428 : {
2429 13 : opt->global_ret = EXIT_FAILURE;
2430 13 : GNUNET_free (secname);
2431 13 : return;
2432 : }
2433 22 : opt->global_ret = TES_listen_start (cfg,
2434 : secname,
2435 : &cb);
2436 22 : GNUNET_free (secname);
2437 22 : if (0 != opt->global_ret)
2438 0 : return;
2439 22 : sem_init (&worker_sem,
2440 : 0);
2441 22 : GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
2442 : opt);
2443 22 : if (0 == opt->max_workers)
2444 : {
2445 : long lret;
2446 :
2447 0 : lret = sysconf (_SC_NPROCESSORS_CONF);
2448 0 : if (lret <= 0)
2449 0 : lret = 1;
2450 0 : opt->max_workers = (unsigned int) lret;
2451 : }
2452 314 : for (unsigned int i = 0; i<opt->max_workers; i++)
2453 292 : if (GNUNET_OK !=
2454 292 : start_worker ())
2455 : {
2456 0 : GNUNET_SCHEDULER_shutdown ();
2457 0 : return;
2458 : }
2459 : /* Load denominations */
2460 22 : keys = GNUNET_CONTAINER_multihashmap_create (65536,
2461 : true);
2462 : {
2463 22 : struct LoadContext lc = {
2464 : .cfg = cfg,
2465 : .ret = GNUNET_OK,
2466 : .t = opt->global_now,
2467 22 : .cprefix = opt->cprefix
2468 : };
2469 22 : bool wake = true;
2470 :
2471 22 : GNUNET_assert (0 == pthread_mutex_lock (&keys_lock));
2472 22 : GNUNET_CONFIGURATION_iterate_sections (cfg,
2473 : &load_denominations,
2474 : &lc);
2475 22 : GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock));
2476 22 : if (GNUNET_OK != lc.ret)
2477 : {
2478 0 : opt->global_ret = EXIT_FAILURE;
2479 0 : GNUNET_SCHEDULER_shutdown ();
2480 0 : return;
2481 : }
2482 22 : create_missing_keys (opt,
2483 : &wake);
2484 : }
2485 22 : if (NULL == denom_head)
2486 : {
2487 10 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2488 : "No CS denominations configured. Make sure section names start with `%s' if you are using CS!\n",
2489 : opt->cprefix);
2490 10 : TES_wake_clients ();
2491 10 : return;
2492 : }
2493 : /* start job to keep keys up-to-date; MUST be run before the #listen_task,
2494 : hence with priority. */
2495 12 : keygen_task = GNUNET_SCHEDULER_add_with_priority (
2496 : GNUNET_SCHEDULER_PRIORITY_URGENT,
2497 : &update_denominations,
2498 : opt);
2499 : }
|