Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2020, 2021, 2022 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU 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/crypto_helper_cs.c
18 : * @brief utility functions for running out-of-process private key operations
19 : * @author Christian Grothoff
20 : */
21 : #include "platform.h"
22 : #include "taler/taler_util.h"
23 : #include "taler/taler_signatures.h"
24 : #include "secmod_cs.h"
25 : #include <poll.h>
26 : #include "crypto_helper_common.h"
27 :
28 :
29 : struct TALER_CRYPTO_CsDenominationHelper
30 : {
31 : /**
32 : * Function to call with updates to available key material.
33 : */
34 : TALER_CRYPTO_CsDenominationKeyStatusCallback dkc;
35 :
36 : /**
37 : * Closure for @e dkc
38 : */
39 : void *dkc_cls;
40 :
41 : /**
42 : * Socket address of the denomination helper process.
43 : * Used to reconnect if the connection breaks.
44 : */
45 : struct sockaddr_un sa;
46 :
47 : /**
48 : * The UNIX domain socket, -1 if we are currently not connected.
49 : */
50 : int sock;
51 :
52 : /**
53 : * Have we ever been sync'ed?
54 : */
55 : bool synced;
56 : };
57 :
58 :
59 : /**
60 : * Disconnect from the helper process. Updates
61 : * @e sock field in @a dh.
62 : *
63 : * @param[in,out] dh handle to tear down connection of
64 : */
65 : static void
66 27 : do_disconnect (struct TALER_CRYPTO_CsDenominationHelper *dh)
67 : {
68 27 : GNUNET_break (0 == close (dh->sock));
69 27 : dh->sock = -1;
70 27 : dh->synced = false;
71 27 : }
72 :
73 :
74 : /**
75 : * Try to connect to the helper process. Updates
76 : * @e sock field in @a dh.
77 : *
78 : * @param[in,out] dh handle to establish connection for
79 : * @return #GNUNET_OK on success
80 : */
81 : static enum GNUNET_GenericReturnValue
82 1876 : try_connect (struct TALER_CRYPTO_CsDenominationHelper *dh)
83 : {
84 1876 : if (-1 != dh->sock)
85 1849 : return GNUNET_OK;
86 27 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
87 : "Establishing connection!\n");
88 27 : dh->sock = socket (AF_UNIX,
89 : SOCK_STREAM,
90 : 0);
91 27 : if (-1 == dh->sock)
92 : {
93 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
94 : "socket");
95 0 : return GNUNET_SYSERR;
96 : }
97 27 : if (0 !=
98 27 : connect (dh->sock,
99 27 : (const struct sockaddr *) &dh->sa,
100 : sizeof (dh->sa)))
101 : {
102 1 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
103 : "connect",
104 : dh->sa.sun_path);
105 1 : do_disconnect (dh);
106 1 : return GNUNET_SYSERR;
107 : }
108 26 : TALER_CRYPTO_helper_cs_poll (dh);
109 26 : return GNUNET_OK;
110 : }
111 :
112 :
113 : struct TALER_CRYPTO_CsDenominationHelper *
114 27 : TALER_CRYPTO_helper_cs_connect (
115 : const struct GNUNET_CONFIGURATION_Handle *cfg,
116 : const char *section,
117 : TALER_CRYPTO_CsDenominationKeyStatusCallback dkc,
118 : void *dkc_cls)
119 : {
120 : struct TALER_CRYPTO_CsDenominationHelper *dh;
121 : char *unixpath;
122 : char *secname;
123 :
124 27 : GNUNET_asprintf (&secname,
125 : "%s-secmod-cs",
126 : section);
127 27 : if (GNUNET_OK !=
128 27 : GNUNET_CONFIGURATION_get_value_filename (cfg,
129 : secname,
130 : "UNIXPATH",
131 : &unixpath))
132 : {
133 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
134 : secname,
135 : "UNIXPATH");
136 0 : GNUNET_free (secname);
137 0 : return NULL;
138 : }
139 : /* we use >= here because we want the sun_path to always
140 : be 0-terminated */
141 27 : if (strlen (unixpath) >= sizeof (dh->sa.sun_path))
142 : {
143 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
144 : secname,
145 : "UNIXPATH",
146 : "path too long");
147 0 : GNUNET_free (unixpath);
148 0 : GNUNET_free (secname);
149 0 : return NULL;
150 : }
151 27 : GNUNET_free (secname);
152 27 : dh = GNUNET_new (struct TALER_CRYPTO_CsDenominationHelper);
153 27 : dh->dkc = dkc;
154 27 : dh->dkc_cls = dkc_cls;
155 27 : dh->sa.sun_family = AF_UNIX;
156 27 : strncpy (dh->sa.sun_path,
157 : unixpath,
158 : sizeof (dh->sa.sun_path) - 1);
159 27 : GNUNET_free (unixpath);
160 27 : dh->sock = -1;
161 27 : if (GNUNET_OK !=
162 27 : try_connect (dh))
163 : {
164 1 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
165 : "Could not connect to %s. Will keep trying\n",
166 : "taler-exchange-helper-secmod-cs");
167 : }
168 27 : return dh;
169 : }
170 :
171 :
172 : /**
173 : * Handle a #TALER_HELPER_CS_MT_AVAIL message from the helper.
174 : *
175 : * @param dh helper context
176 : * @param hdr message that we received
177 : * @return #GNUNET_OK on success
178 : */
179 : static enum GNUNET_GenericReturnValue
180 283 : handle_mt_avail (struct TALER_CRYPTO_CsDenominationHelper *dh,
181 : const struct GNUNET_MessageHeader *hdr)
182 : {
183 283 : const struct TALER_CRYPTO_CsKeyAvailableNotification *kan
184 : = (const struct TALER_CRYPTO_CsKeyAvailableNotification *) hdr;
185 283 : const char *buf = (const char *) &kan[1];
186 : const char *section_name;
187 : uint16_t snl;
188 :
189 283 : if (sizeof (*kan) > ntohs (hdr->size))
190 : {
191 0 : GNUNET_break_op (0);
192 0 : return GNUNET_SYSERR;
193 : }
194 283 : snl = ntohs (kan->section_name_len);
195 283 : if (ntohs (hdr->size) != sizeof (*kan) + snl)
196 : {
197 0 : GNUNET_break_op (0);
198 0 : return GNUNET_SYSERR;
199 : }
200 283 : if (0 == snl)
201 : {
202 0 : GNUNET_break_op (0);
203 0 : return GNUNET_SYSERR;
204 : }
205 283 : section_name = buf;
206 283 : if ('\0' != section_name[snl - 1])
207 : {
208 0 : GNUNET_break_op (0);
209 0 : return GNUNET_SYSERR;
210 : }
211 :
212 : {
213 : struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub;
214 : struct TALER_CsPubHashP h_cs;
215 :
216 283 : bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
217 283 : bsign_pub->cipher = GNUNET_CRYPTO_BSA_CS;
218 283 : bsign_pub->rc = 1;
219 283 : bsign_pub->details.cs_public_key = kan->denom_pub;
220 :
221 283 : GNUNET_CRYPTO_hash (&bsign_pub->details.cs_public_key,
222 : sizeof (bsign_pub->details.cs_public_key),
223 : &bsign_pub->pub_key_hash);
224 283 : h_cs.hash = bsign_pub->pub_key_hash;
225 283 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
226 : "Received CS key %s (%s)\n",
227 : GNUNET_h2s (&h_cs.hash),
228 : section_name);
229 283 : if (GNUNET_OK !=
230 283 : TALER_exchange_secmod_cs_verify (
231 : &h_cs,
232 : section_name,
233 : GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
234 : GNUNET_TIME_relative_ntoh (kan->duration_withdraw),
235 : &kan->secm_pub,
236 : &kan->secm_sig))
237 : {
238 0 : GNUNET_break_op (0);
239 0 : GNUNET_CRYPTO_blind_sign_pub_decref (bsign_pub);
240 0 : return GNUNET_SYSERR;
241 : }
242 283 : dh->dkc (dh->dkc_cls,
243 : section_name,
244 : GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
245 : GNUNET_TIME_relative_ntoh (kan->duration_withdraw),
246 : &h_cs,
247 : bsign_pub,
248 : &kan->secm_pub,
249 : &kan->secm_sig);
250 283 : GNUNET_CRYPTO_blind_sign_pub_decref (bsign_pub);
251 : }
252 283 : return GNUNET_OK;
253 : }
254 :
255 :
256 : /**
257 : * Handle a #TALER_HELPER_CS_MT_PURGE message from the helper.
258 : *
259 : * @param dh helper context
260 : * @param hdr message that we received
261 : * @return #GNUNET_OK on success
262 : */
263 : static enum GNUNET_GenericReturnValue
264 3 : handle_mt_purge (struct TALER_CRYPTO_CsDenominationHelper *dh,
265 : const struct GNUNET_MessageHeader *hdr)
266 : {
267 3 : const struct TALER_CRYPTO_CsKeyPurgeNotification *pn
268 : = (const struct TALER_CRYPTO_CsKeyPurgeNotification *) hdr;
269 :
270 3 : if (sizeof (*pn) != ntohs (hdr->size))
271 : {
272 0 : GNUNET_break_op (0);
273 0 : return GNUNET_SYSERR;
274 : }
275 3 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
276 : "Received revocation of denomination key %s\n",
277 : GNUNET_h2s (&pn->h_cs.hash));
278 3 : dh->dkc (dh->dkc_cls,
279 : NULL,
280 3 : GNUNET_TIME_UNIT_ZERO_TS,
281 3 : GNUNET_TIME_UNIT_ZERO,
282 : &pn->h_cs,
283 : NULL,
284 : NULL,
285 : NULL);
286 3 : return GNUNET_OK;
287 : }
288 :
289 :
290 : void
291 738 : TALER_CRYPTO_helper_cs_poll (struct TALER_CRYPTO_CsDenominationHelper *dh)
292 : {
293 : char buf[UINT16_MAX];
294 738 : size_t off = 0;
295 738 : unsigned int retry_limit = 3;
296 738 : const struct GNUNET_MessageHeader *hdr
297 : = (const struct GNUNET_MessageHeader *) buf;
298 :
299 738 : if (GNUNET_OK !=
300 738 : try_connect (dh))
301 0 : return; /* give up */
302 : while (1)
303 34 : {
304 : uint16_t msize;
305 : ssize_t ret;
306 :
307 772 : ret = recv (dh->sock,
308 : buf + off,
309 : sizeof (buf) - off,
310 772 : (dh->synced && (0 == off))
311 : ? MSG_DONTWAIT
312 : : 0);
313 772 : if (ret < 0)
314 : {
315 738 : if (EINTR == errno)
316 0 : continue;
317 738 : if (EAGAIN == errno)
318 : {
319 738 : GNUNET_assert (dh->synced);
320 738 : GNUNET_assert (0 == off);
321 738 : break;
322 : }
323 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
324 : "recv");
325 0 : do_disconnect (dh);
326 0 : if (0 == retry_limit)
327 0 : return; /* give up */
328 0 : if (GNUNET_OK !=
329 0 : try_connect (dh))
330 0 : return; /* give up */
331 0 : retry_limit--;
332 0 : continue;
333 : }
334 34 : if (0 == ret)
335 : {
336 0 : GNUNET_break (0 == off);
337 0 : return;
338 : }
339 34 : off += ret;
340 346 : more:
341 346 : if (off < sizeof (struct GNUNET_MessageHeader))
342 34 : continue;
343 312 : msize = ntohs (hdr->size);
344 312 : if (off < msize)
345 0 : continue;
346 312 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
347 : "Received message of type %u and length %u\n",
348 : (unsigned int) ntohs (hdr->type),
349 : (unsigned int) msize);
350 312 : switch (ntohs (hdr->type))
351 : {
352 283 : case TALER_HELPER_CS_MT_AVAIL:
353 283 : if (GNUNET_OK !=
354 283 : handle_mt_avail (dh,
355 : hdr))
356 : {
357 0 : GNUNET_break_op (0);
358 0 : do_disconnect (dh);
359 0 : return;
360 : }
361 283 : break;
362 3 : case TALER_HELPER_CS_MT_PURGE:
363 3 : if (GNUNET_OK !=
364 3 : handle_mt_purge (dh,
365 : hdr))
366 : {
367 0 : GNUNET_break_op (0);
368 0 : do_disconnect (dh);
369 0 : return;
370 : }
371 3 : break;
372 26 : case TALER_HELPER_CS_SYNCED:
373 26 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
374 : "Now synchronized with CS helper\n");
375 26 : dh->synced = true;
376 26 : break;
377 0 : default:
378 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
379 : "Received unexpected message of type %d (len: %u)\n",
380 : (unsigned int) ntohs (hdr->type),
381 : (unsigned int) msize);
382 0 : GNUNET_break_op (0);
383 0 : do_disconnect (dh);
384 0 : return;
385 : }
386 312 : memmove (buf,
387 312 : &buf[msize],
388 : off - msize);
389 312 : off -= msize;
390 312 : goto more;
391 : }
392 : }
393 :
394 :
395 : void
396 3 : TALER_CRYPTO_helper_cs_revoke (
397 : struct TALER_CRYPTO_CsDenominationHelper *dh,
398 : const struct TALER_CsPubHashP *h_cs)
399 : {
400 3 : struct TALER_CRYPTO_CsRevokeRequest rr = {
401 3 : .header.size = htons (sizeof (rr)),
402 3 : .header.type = htons (TALER_HELPER_CS_MT_REQ_REVOKE),
403 : .h_cs = *h_cs
404 : };
405 :
406 3 : if (GNUNET_OK !=
407 3 : try_connect (dh))
408 0 : return; /* give up */
409 3 : if (GNUNET_OK !=
410 3 : TALER_crypto_helper_send_all (dh->sock,
411 : &rr,
412 : sizeof (rr)))
413 : {
414 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
415 : "send");
416 0 : do_disconnect (dh);
417 0 : return;
418 : }
419 3 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
420 : "Requested revocation of denomination key %s\n",
421 : GNUNET_h2s (&h_cs->hash));
422 : }
423 :
424 :
425 : enum TALER_ErrorCode
426 959 : TALER_CRYPTO_helper_cs_batch_sign (
427 : struct TALER_CRYPTO_CsDenominationHelper *dh,
428 : unsigned int reqs_length,
429 : const struct TALER_CRYPTO_CsSignRequest reqs[static reqs_length],
430 : bool for_melt,
431 : struct TALER_BlindedDenominationSignature bss[static reqs_length])
432 959 : {
433 959 : enum TALER_ErrorCode ec = TALER_EC_INVALID;
434 : unsigned int rpos;
435 : unsigned int rend;
436 : unsigned int wpos;
437 :
438 959 : memset (bss,
439 : 0,
440 : sizeof (*bss) * reqs_length);
441 959 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
442 : "Starting signature process\n");
443 959 : if (GNUNET_OK !=
444 959 : try_connect (dh))
445 : {
446 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
447 : "Failed to connect to helper\n");
448 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
449 : }
450 :
451 959 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
452 : "Requesting %u signatures\n",
453 : reqs_length);
454 959 : rpos = 0;
455 959 : rend = 0;
456 959 : wpos = 0;
457 1918 : while (rpos < reqs_length)
458 : {
459 959 : unsigned int mlen = sizeof (struct TALER_CRYPTO_BatchSignRequest);
460 :
461 2111 : while ( (rend < reqs_length) &&
462 1152 : (mlen + sizeof (struct TALER_CRYPTO_CsSignRequestMessage)
463 : < UINT16_MAX) )
464 : {
465 1152 : mlen += sizeof (struct TALER_CRYPTO_CsSignRequestMessage);
466 1152 : rend++;
467 : }
468 959 : {
469 959 : char obuf[mlen] GNUNET_ALIGN;
470 959 : struct TALER_CRYPTO_BatchSignRequest *bsr
471 : = (struct TALER_CRYPTO_BatchSignRequest *) obuf;
472 : void *wbuf;
473 :
474 959 : bsr->header.type = htons (TALER_HELPER_CS_MT_REQ_BATCH_SIGN);
475 959 : bsr->header.size = htons (mlen);
476 959 : bsr->batch_size = htonl (rend - rpos);
477 959 : wbuf = &bsr[1];
478 2111 : for (unsigned int i = rpos; i<rend; i++)
479 : {
480 1152 : struct TALER_CRYPTO_CsSignRequestMessage *csm = wbuf;
481 1152 : const struct TALER_CRYPTO_CsSignRequest *csr = &reqs[i];
482 :
483 1152 : csm->header.size = htons (sizeof (*csm));
484 1152 : csm->header.type = htons (TALER_HELPER_CS_MT_REQ_SIGN);
485 1152 : csm->for_melt = htonl (for_melt ? 1 : 0);
486 1152 : csm->h_cs = *csr->h_cs;
487 1152 : csm->message = *csr->blinded_planchet;
488 1152 : wbuf += sizeof (*csm);
489 : }
490 959 : GNUNET_assert (wbuf == &obuf[mlen]);
491 959 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
492 : "Sending batch request [%u-%u)\n",
493 : rpos,
494 : rend);
495 959 : if (GNUNET_OK !=
496 959 : TALER_crypto_helper_send_all (dh->sock,
497 : obuf,
498 959 : sizeof (obuf)))
499 : {
500 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
501 : "send");
502 0 : do_disconnect (dh);
503 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
504 : }
505 : } /* end of obuf scope */
506 959 : rpos = rend;
507 : {
508 : char buf[UINT16_MAX];
509 959 : size_t off = 0;
510 959 : const struct GNUNET_MessageHeader *hdr
511 : = (const struct GNUNET_MessageHeader *) buf;
512 959 : bool finished = false;
513 :
514 : while (1)
515 1053 : {
516 : uint16_t msize;
517 : ssize_t ret;
518 :
519 2012 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
520 : "Awaiting reply at %u (up to %u)\n",
521 : wpos,
522 : rend);
523 2971 : ret = recv (dh->sock,
524 2012 : &buf[off],
525 : sizeof (buf) - off,
526 959 : (finished && (0 == off))
527 : ? MSG_DONTWAIT
528 : : 0);
529 2012 : if (ret < 0)
530 : {
531 959 : if (EINTR == errno)
532 0 : continue;
533 959 : if (EAGAIN == errno)
534 : {
535 959 : GNUNET_assert (finished);
536 959 : GNUNET_assert (0 == off);
537 959 : break;
538 : }
539 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
540 : "recv");
541 0 : do_disconnect (dh);
542 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
543 : }
544 1053 : if (0 == ret)
545 : {
546 0 : GNUNET_break (0 == off);
547 0 : if (! finished)
548 0 : return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
549 0 : if (TALER_EC_NONE == ec)
550 0 : break;
551 0 : return ec;
552 : }
553 1053 : off += ret;
554 2205 : more:
555 2205 : if (off < sizeof (struct GNUNET_MessageHeader))
556 1053 : continue;
557 1152 : msize = ntohs (hdr->size);
558 1152 : if (off < msize)
559 0 : continue;
560 1152 : switch (ntohs (hdr->type))
561 : {
562 1149 : case TALER_HELPER_CS_MT_RES_SIGNATURE:
563 1149 : if (msize != sizeof (struct TALER_CRYPTO_SignResponse))
564 : {
565 0 : GNUNET_break_op (0);
566 0 : do_disconnect (dh);
567 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
568 : }
569 1149 : if (finished)
570 : {
571 0 : GNUNET_break_op (0);
572 0 : do_disconnect (dh);
573 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
574 : }
575 : {
576 1149 : const struct TALER_CRYPTO_SignResponse *sr =
577 : (const struct TALER_CRYPTO_SignResponse *) buf;
578 : struct GNUNET_CRYPTO_BlindedSignature *blinded_sig;
579 1149 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
580 : "Received %u signature\n",
581 : wpos);
582 1149 : blinded_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
583 1149 : blinded_sig->cipher = GNUNET_CRYPTO_BSA_CS;
584 1149 : blinded_sig->rc = 1;
585 1149 : blinded_sig->details.blinded_cs_answer.b = ntohl (sr->b);
586 1149 : blinded_sig->details.blinded_cs_answer.s_scalar = sr->cs_answer;
587 :
588 1149 : bss[wpos].blinded_sig = blinded_sig;
589 1149 : wpos++;
590 1149 : if (wpos == rend)
591 : {
592 956 : if (TALER_EC_INVALID == ec)
593 956 : ec = TALER_EC_NONE;
594 956 : finished = true;
595 : }
596 1149 : break;
597 : }
598 :
599 3 : case TALER_HELPER_CS_MT_RES_SIGN_FAILURE:
600 3 : if (msize != sizeof (struct TALER_CRYPTO_SignFailure))
601 : {
602 0 : GNUNET_break_op (0);
603 0 : do_disconnect (dh);
604 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
605 : }
606 : {
607 3 : const struct TALER_CRYPTO_SignFailure *sf =
608 : (const struct TALER_CRYPTO_SignFailure *) buf;
609 :
610 3 : ec = (enum TALER_ErrorCode) (int) ntohl (sf->ec);
611 3 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
612 : "Signing %u failed with status %d!\n",
613 : wpos,
614 : ec);
615 3 : wpos++;
616 3 : if (wpos == rend)
617 : {
618 3 : finished = true;
619 : }
620 3 : break;
621 : }
622 0 : case TALER_HELPER_CS_MT_AVAIL:
623 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
624 : "Received new key!\n");
625 0 : if (GNUNET_OK !=
626 0 : handle_mt_avail (dh,
627 : hdr))
628 : {
629 0 : GNUNET_break_op (0);
630 0 : do_disconnect (dh);
631 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
632 : }
633 0 : break; /* while(1) loop ensures we recvfrom() again */
634 0 : case TALER_HELPER_CS_MT_PURGE:
635 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
636 : "Received revocation!\n");
637 0 : if (GNUNET_OK !=
638 0 : handle_mt_purge (dh,
639 : hdr))
640 : {
641 0 : GNUNET_break_op (0);
642 0 : do_disconnect (dh);
643 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
644 : }
645 0 : break; /* while(1) loop ensures we recvfrom() again */
646 0 : case TALER_HELPER_CS_SYNCED:
647 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
648 : "Synchronized add odd time with CS helper!\n");
649 0 : dh->synced = true;
650 0 : break;
651 0 : default:
652 0 : GNUNET_break_op (0);
653 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
654 : "Received unexpected message of type %u\n",
655 : ntohs (hdr->type));
656 0 : do_disconnect (dh);
657 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
658 : }
659 1152 : memmove (buf,
660 1152 : &buf[msize],
661 : off - msize);
662 1152 : off -= msize;
663 1152 : goto more;
664 : } /* while(1) */
665 : } /* scope */
666 : } /* while (rpos < cdrs_length) */
667 959 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
668 : "Existing with %u signatures and status %d\n",
669 : wpos,
670 : ec);
671 959 : return ec;
672 : }
673 :
674 :
675 : enum TALER_ErrorCode
676 149 : TALER_CRYPTO_helper_cs_r_batch_derive (
677 : struct TALER_CRYPTO_CsDenominationHelper *dh,
678 : unsigned int cdrs_length,
679 : const struct TALER_CRYPTO_CsDeriveRequest cdrs[static cdrs_length],
680 : bool for_melt,
681 : struct GNUNET_CRYPTO_CSPublicRPairP crps[static cdrs_length])
682 149 : {
683 149 : enum TALER_ErrorCode ec = TALER_EC_INVALID;
684 : unsigned int rpos;
685 : unsigned int rend;
686 : unsigned int wpos;
687 :
688 149 : memset (crps,
689 : 0,
690 : sizeof (*crps) * cdrs_length);
691 149 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
692 : "Starting R derivation process\n");
693 149 : if (GNUNET_OK !=
694 149 : try_connect (dh))
695 : {
696 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
697 : "Failed to connect to helper\n");
698 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
699 : }
700 :
701 149 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
702 : "Requesting %u R pairs\n",
703 : cdrs_length);
704 149 : rpos = 0;
705 149 : rend = 0;
706 149 : wpos = 0;
707 298 : while (rpos < cdrs_length)
708 : {
709 149 : unsigned int mlen = sizeof (struct TALER_CRYPTO_BatchDeriveRequest);
710 :
711 1119 : while ( (rend < cdrs_length) &&
712 970 : (mlen + sizeof (struct TALER_CRYPTO_CsRDeriveRequest)
713 : < UINT16_MAX) )
714 : {
715 970 : mlen += sizeof (struct TALER_CRYPTO_CsRDeriveRequest);
716 970 : rend++;
717 : }
718 149 : {
719 149 : char obuf[mlen] GNUNET_ALIGN;
720 149 : struct TALER_CRYPTO_BatchDeriveRequest *bdr
721 : = (struct TALER_CRYPTO_BatchDeriveRequest *) obuf;
722 : void *wbuf;
723 :
724 149 : bdr->header.type = htons (TALER_HELPER_CS_MT_REQ_BATCH_RDERIVE);
725 149 : bdr->header.size = htons (mlen);
726 149 : bdr->batch_size = htonl (rend - rpos);
727 149 : wbuf = &bdr[1];
728 1119 : for (unsigned int i = rpos; i<rend; i++)
729 : {
730 970 : struct TALER_CRYPTO_CsRDeriveRequest *rdr = wbuf;
731 970 : const struct TALER_CRYPTO_CsDeriveRequest *cdr = &cdrs[i];
732 :
733 970 : rdr->header.size = htons (sizeof (*rdr));
734 970 : rdr->header.type = htons (TALER_HELPER_CS_MT_REQ_RDERIVE);
735 970 : rdr->for_melt = htonl (for_melt ? 1 : 0);
736 970 : rdr->h_cs = *cdr->h_cs;
737 970 : rdr->nonce = *cdr->nonce;
738 970 : wbuf += sizeof (*rdr);
739 : }
740 149 : GNUNET_assert (wbuf == &obuf[mlen]);
741 149 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
742 : "Sending batch request [%u-%u)\n",
743 : rpos,
744 : rend);
745 149 : if (GNUNET_OK !=
746 149 : TALER_crypto_helper_send_all (dh->sock,
747 : obuf,
748 149 : sizeof (obuf)))
749 : {
750 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
751 : "send");
752 0 : do_disconnect (dh);
753 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
754 : }
755 : } /* end of obuf scope */
756 149 : rpos = rend;
757 : {
758 : char buf[UINT16_MAX];
759 149 : size_t off = 0;
760 149 : const struct GNUNET_MessageHeader *hdr
761 : = (const struct GNUNET_MessageHeader *) buf;
762 149 : bool finished = false;
763 :
764 : while (1)
765 488 : {
766 : uint16_t msize;
767 : ssize_t ret;
768 :
769 637 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
770 : "Awaiting reply at %u (up to %u)\n",
771 : wpos,
772 : rend);
773 786 : ret = recv (dh->sock,
774 637 : &buf[off],
775 : sizeof (buf) - off,
776 149 : (finished && (0 == off))
777 : ? MSG_DONTWAIT
778 : : 0);
779 637 : if (ret < 0)
780 : {
781 149 : if (EINTR == errno)
782 0 : continue;
783 149 : if (EAGAIN == errno)
784 : {
785 149 : GNUNET_assert (finished);
786 149 : GNUNET_assert (0 == off);
787 149 : break;
788 : }
789 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
790 : "recv");
791 0 : do_disconnect (dh);
792 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
793 : }
794 488 : if (0 == ret)
795 : {
796 0 : GNUNET_break (0 == off);
797 0 : if (! finished)
798 0 : return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
799 0 : if (TALER_EC_NONE == ec)
800 0 : break;
801 0 : return ec;
802 : }
803 488 : off += ret;
804 1458 : more:
805 1458 : if (off < sizeof (struct GNUNET_MessageHeader))
806 488 : continue;
807 970 : msize = ntohs (hdr->size);
808 970 : if (off < msize)
809 0 : continue;
810 970 : switch (ntohs (hdr->type))
811 : {
812 357 : case TALER_HELPER_CS_MT_RES_RDERIVE:
813 357 : if (msize != sizeof (struct TALER_CRYPTO_RDeriveResponse))
814 : {
815 0 : GNUNET_break_op (0);
816 0 : do_disconnect (dh);
817 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
818 : }
819 357 : if (finished)
820 : {
821 0 : GNUNET_break_op (0);
822 0 : do_disconnect (dh);
823 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
824 : }
825 : {
826 357 : const struct TALER_CRYPTO_RDeriveResponse *rdr =
827 : (const struct TALER_CRYPTO_RDeriveResponse *) buf;
828 :
829 357 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
830 : "Received %u R pair\n",
831 : wpos);
832 357 : crps[wpos] = rdr->r_pub;
833 357 : wpos++;
834 357 : if (wpos == rend)
835 : {
836 116 : if (TALER_EC_INVALID == ec)
837 116 : ec = TALER_EC_NONE;
838 116 : finished = true;
839 : }
840 357 : break;
841 : }
842 613 : case TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE:
843 613 : if (msize != sizeof (struct TALER_CRYPTO_RDeriveFailure))
844 : {
845 0 : GNUNET_break_op (0);
846 0 : do_disconnect (dh);
847 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
848 : }
849 : {
850 613 : const struct TALER_CRYPTO_RDeriveFailure *rdf =
851 : (const struct TALER_CRYPTO_RDeriveFailure *) buf;
852 :
853 613 : ec = (enum TALER_ErrorCode) (int) ntohl (rdf->ec);
854 613 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
855 : "R derivation %u failed with status %d!\n",
856 : wpos,
857 : ec);
858 613 : wpos++;
859 613 : if (wpos == rend)
860 : {
861 33 : finished = true;
862 : }
863 613 : break;
864 : }
865 0 : case TALER_HELPER_CS_MT_AVAIL:
866 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
867 : "Received new key!\n");
868 0 : if (GNUNET_OK !=
869 0 : handle_mt_avail (dh,
870 : hdr))
871 : {
872 0 : GNUNET_break_op (0);
873 0 : do_disconnect (dh);
874 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
875 : }
876 0 : break; /* while(1) loop ensures we recvfrom() again */
877 0 : case TALER_HELPER_CS_MT_PURGE:
878 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
879 : "Received revocation!\n");
880 0 : if (GNUNET_OK !=
881 0 : handle_mt_purge (dh,
882 : hdr))
883 : {
884 0 : GNUNET_break_op (0);
885 0 : do_disconnect (dh);
886 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
887 : }
888 0 : break; /* while(1) loop ensures we recvfrom() again */
889 0 : case TALER_HELPER_CS_SYNCED:
890 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
891 : "Synchronized add odd time with CS helper!\n");
892 0 : dh->synced = true;
893 0 : break;
894 0 : default:
895 0 : GNUNET_break_op (0);
896 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
897 : "Received unexpected message of type %u\n",
898 : ntohs (hdr->type));
899 0 : do_disconnect (dh);
900 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
901 : }
902 970 : memmove (buf,
903 970 : &buf[msize],
904 : off - msize);
905 970 : off -= msize;
906 970 : goto more;
907 : } /* while(1) */
908 : } /* scope */
909 : } /* while (rpos < cdrs_length) */
910 149 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
911 : "Existing with %u signatures and status %d\n",
912 : wpos,
913 : ec);
914 149 : return ec;
915 : }
916 :
917 :
918 : void
919 27 : TALER_CRYPTO_helper_cs_disconnect (
920 : struct TALER_CRYPTO_CsDenominationHelper *dh)
921 : {
922 27 : if (-1 != dh->sock)
923 26 : do_disconnect (dh);
924 27 : GNUNET_free (dh);
925 27 : }
926 :
927 :
928 : /* end of crypto_helper_cs.c */
|