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 1884 : try_connect (struct TALER_CRYPTO_CsDenominationHelper *dh)
83 : {
84 1884 : if (-1 != dh->sock)
85 1857 : 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 233 : handle_mt_avail (struct TALER_CRYPTO_CsDenominationHelper *dh,
181 : const struct GNUNET_MessageHeader *hdr)
182 : {
183 233 : const struct TALER_CRYPTO_CsKeyAvailableNotification *kan
184 : = (const struct TALER_CRYPTO_CsKeyAvailableNotification *) hdr;
185 233 : const char *buf = (const char *) &kan[1];
186 : const char *section_name;
187 : uint32_t snl;
188 :
189 233 : if (sizeof (*kan) > ntohs (hdr->size))
190 : {
191 0 : GNUNET_break_op (0);
192 0 : return GNUNET_SYSERR;
193 : }
194 233 : snl = ntohl (kan->section_name_len);
195 233 : if (ntohs (hdr->size) != sizeof (*kan) + snl)
196 : {
197 0 : GNUNET_break_op (0);
198 0 : return GNUNET_SYSERR;
199 : }
200 233 : if (0 == snl)
201 : {
202 0 : GNUNET_break_op (0);
203 0 : return GNUNET_SYSERR;
204 : }
205 233 : section_name = buf;
206 233 : 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 233 : bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey);
217 233 : bsign_pub->cipher = GNUNET_CRYPTO_BSA_CS;
218 233 : bsign_pub->rc = 1;
219 233 : bsign_pub->details.cs_public_key = kan->denom_pub;
220 :
221 233 : GNUNET_CRYPTO_hash (&bsign_pub->details.cs_public_key,
222 : sizeof (bsign_pub->details.cs_public_key),
223 : &bsign_pub->pub_key_hash);
224 233 : h_cs.hash = bsign_pub->pub_key_hash;
225 233 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
226 : "Received CS key %s (%s)\n",
227 : GNUNET_h2s (&h_cs.hash),
228 : section_name);
229 233 : if (GNUNET_OK !=
230 233 : 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 233 : 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 233 : GNUNET_CRYPTO_blind_sign_pub_decref (bsign_pub);
251 : }
252 233 : 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 36 : {
304 : uint16_t msize;
305 : ssize_t ret;
306 :
307 774 : ret = recv (dh->sock,
308 : buf + off,
309 : sizeof (buf) - off,
310 774 : (dh->synced && (0 == off))
311 : ? MSG_DONTWAIT
312 : : 0);
313 774 : 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 36 : if (0 == ret)
335 : {
336 0 : GNUNET_break (0 == off);
337 0 : return;
338 : }
339 36 : off += ret;
340 298 : more:
341 298 : if (off < sizeof (struct GNUNET_MessageHeader))
342 36 : continue;
343 262 : msize = ntohs (hdr->size);
344 262 : if (msize < sizeof (struct GNUNET_MessageHeader))
345 : {
346 0 : GNUNET_break_op (0);
347 0 : do_disconnect (dh);
348 0 : return;
349 : }
350 262 : if (off < msize)
351 0 : continue;
352 262 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
353 : "Received message of type %u and length %u\n",
354 : (unsigned int) ntohs (hdr->type),
355 : (unsigned int) msize);
356 262 : switch (ntohs (hdr->type))
357 : {
358 233 : case TALER_HELPER_CS_MT_AVAIL:
359 233 : if (GNUNET_OK !=
360 233 : handle_mt_avail (dh,
361 : hdr))
362 : {
363 0 : GNUNET_break_op (0);
364 0 : do_disconnect (dh);
365 0 : return;
366 : }
367 233 : break;
368 3 : case TALER_HELPER_CS_MT_PURGE:
369 3 : if (GNUNET_OK !=
370 3 : handle_mt_purge (dh,
371 : hdr))
372 : {
373 0 : GNUNET_break_op (0);
374 0 : do_disconnect (dh);
375 0 : return;
376 : }
377 3 : break;
378 26 : case TALER_HELPER_CS_SYNCED:
379 26 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
380 : "Now synchronized with CS helper\n");
381 26 : dh->synced = true;
382 26 : break;
383 0 : default:
384 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
385 : "Received unexpected message of type %d (len: %u)\n",
386 : (unsigned int) ntohs (hdr->type),
387 : (unsigned int) msize);
388 0 : GNUNET_break_op (0);
389 0 : do_disconnect (dh);
390 0 : return;
391 : }
392 262 : memmove (buf,
393 262 : &buf[msize],
394 : off - msize);
395 262 : off -= msize;
396 262 : goto more;
397 : }
398 : }
399 :
400 :
401 : void
402 3 : TALER_CRYPTO_helper_cs_revoke (
403 : struct TALER_CRYPTO_CsDenominationHelper *dh,
404 : const struct TALER_CsPubHashP *h_cs)
405 : {
406 3 : struct TALER_CRYPTO_CsRevokeRequest rr = {
407 3 : .header.size = htons (sizeof (rr)),
408 3 : .header.type = htons (TALER_HELPER_CS_MT_REQ_REVOKE),
409 : .h_cs = *h_cs
410 : };
411 :
412 3 : if (GNUNET_OK !=
413 3 : try_connect (dh))
414 0 : return; /* give up */
415 3 : if (GNUNET_OK !=
416 3 : TALER_crypto_helper_send_all (dh->sock,
417 : &rr,
418 : sizeof (rr)))
419 : {
420 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
421 : "send");
422 0 : do_disconnect (dh);
423 0 : return;
424 : }
425 3 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
426 : "Requested revocation of denomination key %s\n",
427 : GNUNET_h2s (&h_cs->hash));
428 : }
429 :
430 :
431 : enum TALER_ErrorCode
432 959 : TALER_CRYPTO_helper_cs_batch_sign (
433 : struct TALER_CRYPTO_CsDenominationHelper *dh,
434 : unsigned int reqs_length,
435 : const struct TALER_CRYPTO_CsSignRequest reqs[static reqs_length],
436 : bool for_melt,
437 : struct TALER_BlindedDenominationSignature bss[static reqs_length])
438 959 : {
439 959 : enum TALER_ErrorCode ec = TALER_EC_INVALID;
440 : unsigned int rpos;
441 : unsigned int rend;
442 : unsigned int wpos;
443 :
444 959 : memset (bss,
445 : 0,
446 : sizeof (*bss) * reqs_length);
447 959 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
448 : "Starting signature process\n");
449 959 : if (GNUNET_OK !=
450 959 : try_connect (dh))
451 : {
452 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
453 : "Failed to connect to helper\n");
454 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
455 : }
456 :
457 959 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
458 : "Requesting %u signatures\n",
459 : reqs_length);
460 959 : rpos = 0;
461 959 : rend = 0;
462 959 : wpos = 0;
463 1918 : while (rpos < reqs_length)
464 : {
465 959 : unsigned int mlen = sizeof (struct TALER_CRYPTO_BatchSignRequest);
466 :
467 2111 : while ( (rend < reqs_length) &&
468 1152 : (mlen + sizeof (struct TALER_CRYPTO_CsSignRequestMessage)
469 : < UINT16_MAX) )
470 : {
471 1152 : mlen += sizeof (struct TALER_CRYPTO_CsSignRequestMessage);
472 1152 : rend++;
473 : }
474 959 : {
475 959 : char obuf[mlen] GNUNET_ALIGN;
476 959 : struct TALER_CRYPTO_BatchSignRequest *bsr
477 : = (struct TALER_CRYPTO_BatchSignRequest *) obuf;
478 : void *wbuf;
479 :
480 959 : bsr->header.type = htons (TALER_HELPER_CS_MT_REQ_BATCH_SIGN);
481 959 : bsr->header.size = htons (mlen);
482 959 : bsr->batch_size = htonl (rend - rpos);
483 959 : wbuf = &bsr[1];
484 2111 : for (unsigned int i = rpos; i<rend; i++)
485 : {
486 1152 : struct TALER_CRYPTO_CsSignRequestMessage *csm = wbuf;
487 1152 : const struct TALER_CRYPTO_CsSignRequest *csr = &reqs[i];
488 :
489 1152 : csm->header.size = htons (sizeof (*csm));
490 1152 : csm->header.type = htons (TALER_HELPER_CS_MT_REQ_SIGN);
491 1152 : csm->for_melt = htonl (for_melt ? 1 : 0);
492 1152 : csm->h_cs = *csr->h_cs;
493 1152 : csm->message = *csr->blinded_planchet;
494 1152 : wbuf += sizeof (*csm);
495 : }
496 959 : GNUNET_assert (wbuf == &obuf[mlen]);
497 959 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
498 : "Sending batch request [%u-%u)\n",
499 : rpos,
500 : rend);
501 959 : if (GNUNET_OK !=
502 959 : TALER_crypto_helper_send_all (dh->sock,
503 : obuf,
504 959 : sizeof (obuf)))
505 : {
506 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
507 : "send");
508 0 : do_disconnect (dh);
509 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
510 : }
511 : } /* end of obuf scope */
512 959 : rpos = rend;
513 : {
514 : char buf[UINT16_MAX];
515 959 : size_t off = 0;
516 959 : const struct GNUNET_MessageHeader *hdr
517 : = (const struct GNUNET_MessageHeader *) buf;
518 959 : bool finished = false;
519 :
520 : while (1)
521 1041 : {
522 : uint16_t msize;
523 : ssize_t ret;
524 :
525 2000 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
526 : "Awaiting reply at %u (up to %u)\n",
527 : wpos,
528 : rend);
529 2959 : ret = recv (dh->sock,
530 2000 : &buf[off],
531 : sizeof (buf) - off,
532 959 : (finished && (0 == off))
533 : ? MSG_DONTWAIT
534 : : 0);
535 2000 : if (ret < 0)
536 : {
537 959 : if (EINTR == errno)
538 0 : continue;
539 959 : if (EAGAIN == errno)
540 : {
541 959 : GNUNET_assert (finished);
542 959 : GNUNET_assert (0 == off);
543 959 : break;
544 : }
545 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
546 : "recv");
547 0 : do_disconnect (dh);
548 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
549 : }
550 1041 : if (0 == ret)
551 : {
552 0 : GNUNET_break (0 == off);
553 0 : if (! finished)
554 0 : return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
555 0 : if (TALER_EC_NONE == ec)
556 0 : break;
557 0 : return ec;
558 : }
559 1041 : off += ret;
560 2193 : more:
561 2193 : if (off < sizeof (struct GNUNET_MessageHeader))
562 1041 : continue;
563 1152 : msize = ntohs (hdr->size);
564 1152 : if (msize < sizeof (struct GNUNET_MessageHeader))
565 : {
566 0 : GNUNET_break_op (0);
567 0 : do_disconnect (dh);
568 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
569 : }
570 1152 : if (off < msize)
571 0 : continue;
572 1152 : switch (ntohs (hdr->type))
573 : {
574 1149 : case TALER_HELPER_CS_MT_RES_SIGNATURE:
575 1149 : if (msize != sizeof (struct TALER_CRYPTO_SignResponse))
576 : {
577 0 : GNUNET_break_op (0);
578 0 : do_disconnect (dh);
579 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
580 : }
581 1149 : if (finished)
582 : {
583 0 : GNUNET_break_op (0);
584 0 : do_disconnect (dh);
585 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
586 : }
587 : {
588 1149 : const struct TALER_CRYPTO_SignResponse *sr =
589 : (const struct TALER_CRYPTO_SignResponse *) buf;
590 : struct GNUNET_CRYPTO_BlindedSignature *blinded_sig;
591 1149 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
592 : "Received %u signature\n",
593 : wpos);
594 1149 : blinded_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature);
595 1149 : blinded_sig->cipher = GNUNET_CRYPTO_BSA_CS;
596 1149 : blinded_sig->rc = 1;
597 1149 : blinded_sig->details.blinded_cs_answer.b = ntohl (sr->b);
598 1149 : blinded_sig->details.blinded_cs_answer.s_scalar = sr->cs_answer;
599 :
600 1149 : bss[wpos].blinded_sig = blinded_sig;
601 1149 : wpos++;
602 1149 : if (wpos == rend)
603 : {
604 956 : if (TALER_EC_INVALID == ec)
605 956 : ec = TALER_EC_NONE;
606 956 : finished = true;
607 : }
608 1149 : break;
609 : }
610 :
611 3 : case TALER_HELPER_CS_MT_RES_SIGN_FAILURE:
612 3 : if (msize != sizeof (struct TALER_CRYPTO_SignFailure))
613 : {
614 0 : GNUNET_break_op (0);
615 0 : do_disconnect (dh);
616 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
617 : }
618 : {
619 3 : const struct TALER_CRYPTO_SignFailure *sf =
620 : (const struct TALER_CRYPTO_SignFailure *) buf;
621 :
622 3 : ec = (enum TALER_ErrorCode) (int) ntohl (sf->ec);
623 3 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
624 : "Signing %u failed with status %d!\n",
625 : wpos,
626 : ec);
627 3 : wpos++;
628 3 : if (wpos == rend)
629 : {
630 3 : finished = true;
631 : }
632 3 : break;
633 : }
634 0 : case TALER_HELPER_CS_MT_AVAIL:
635 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
636 : "Received new key!\n");
637 0 : if (GNUNET_OK !=
638 0 : handle_mt_avail (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_MT_PURGE:
647 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
648 : "Received revocation!\n");
649 0 : if (GNUNET_OK !=
650 0 : handle_mt_purge (dh,
651 : hdr))
652 : {
653 0 : GNUNET_break_op (0);
654 0 : do_disconnect (dh);
655 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
656 : }
657 0 : break; /* while(1) loop ensures we recvfrom() again */
658 0 : case TALER_HELPER_CS_SYNCED:
659 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
660 : "Synchronized add odd time with CS helper!\n");
661 0 : dh->synced = true;
662 0 : break;
663 0 : default:
664 0 : GNUNET_break_op (0);
665 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
666 : "Received unexpected message of type %u\n",
667 : ntohs (hdr->type));
668 0 : do_disconnect (dh);
669 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
670 : }
671 1152 : memmove (buf,
672 1152 : &buf[msize],
673 : off - msize);
674 1152 : off -= msize;
675 1152 : goto more;
676 : } /* while(1) */
677 : } /* scope */
678 : } /* while (rpos < cdrs_length) */
679 959 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
680 : "Existing with %u signatures and status %d\n",
681 : wpos,
682 : ec);
683 959 : return ec;
684 : }
685 :
686 :
687 : enum TALER_ErrorCode
688 157 : TALER_CRYPTO_helper_cs_r_batch_derive (
689 : struct TALER_CRYPTO_CsDenominationHelper *dh,
690 : unsigned int cdrs_length,
691 : const struct TALER_CRYPTO_CsDeriveRequest cdrs[static cdrs_length],
692 : bool for_melt,
693 : struct GNUNET_CRYPTO_CSPublicRPairP crps[static cdrs_length])
694 157 : {
695 157 : enum TALER_ErrorCode ec = TALER_EC_INVALID;
696 : unsigned int rpos;
697 : unsigned int rend;
698 : unsigned int wpos;
699 :
700 157 : memset (crps,
701 : 0,
702 : sizeof (*crps) * cdrs_length);
703 157 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
704 : "Starting R derivation process\n");
705 157 : if (GNUNET_OK !=
706 157 : try_connect (dh))
707 : {
708 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
709 : "Failed to connect to helper\n");
710 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
711 : }
712 :
713 157 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
714 : "Requesting %u R pairs\n",
715 : cdrs_length);
716 157 : rpos = 0;
717 157 : rend = 0;
718 157 : wpos = 0;
719 314 : while (rpos < cdrs_length)
720 : {
721 157 : unsigned int mlen = sizeof (struct TALER_CRYPTO_BatchDeriveRequest);
722 :
723 1135 : while ( (rend < cdrs_length) &&
724 978 : (mlen + sizeof (struct TALER_CRYPTO_CsRDeriveRequest)
725 : < UINT16_MAX) )
726 : {
727 978 : mlen += sizeof (struct TALER_CRYPTO_CsRDeriveRequest);
728 978 : rend++;
729 : }
730 157 : {
731 157 : char obuf[mlen] GNUNET_ALIGN;
732 157 : struct TALER_CRYPTO_BatchDeriveRequest *bdr
733 : = (struct TALER_CRYPTO_BatchDeriveRequest *) obuf;
734 : void *wbuf;
735 :
736 157 : bdr->header.type = htons (TALER_HELPER_CS_MT_REQ_BATCH_RDERIVE);
737 157 : bdr->header.size = htons (mlen);
738 157 : bdr->batch_size = htonl (rend - rpos);
739 157 : wbuf = &bdr[1];
740 1135 : for (unsigned int i = rpos; i<rend; i++)
741 : {
742 978 : struct TALER_CRYPTO_CsRDeriveRequest *rdr = wbuf;
743 978 : const struct TALER_CRYPTO_CsDeriveRequest *cdr = &cdrs[i];
744 :
745 978 : rdr->header.size = htons (sizeof (*rdr));
746 978 : rdr->header.type = htons (TALER_HELPER_CS_MT_REQ_RDERIVE);
747 978 : rdr->for_melt = htonl (for_melt ? 1 : 0);
748 978 : rdr->h_cs = *cdr->h_cs;
749 978 : rdr->nonce = *cdr->nonce;
750 978 : wbuf += sizeof (*rdr);
751 : }
752 157 : GNUNET_assert (wbuf == &obuf[mlen]);
753 157 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
754 : "Sending batch request [%u-%u)\n",
755 : rpos,
756 : rend);
757 157 : if (GNUNET_OK !=
758 157 : TALER_crypto_helper_send_all (dh->sock,
759 : obuf,
760 157 : sizeof (obuf)))
761 : {
762 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
763 : "send");
764 0 : do_disconnect (dh);
765 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
766 : }
767 : } /* end of obuf scope */
768 157 : rpos = rend;
769 : {
770 : char buf[UINT16_MAX];
771 157 : size_t off = 0;
772 157 : const struct GNUNET_MessageHeader *hdr
773 : = (const struct GNUNET_MessageHeader *) buf;
774 157 : bool finished = false;
775 :
776 : while (1)
777 451 : {
778 : uint16_t msize;
779 : ssize_t ret;
780 :
781 608 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
782 : "Awaiting reply at %u (up to %u)\n",
783 : wpos,
784 : rend);
785 765 : ret = recv (dh->sock,
786 608 : &buf[off],
787 : sizeof (buf) - off,
788 157 : (finished && (0 == off))
789 : ? MSG_DONTWAIT
790 : : 0);
791 608 : if (ret < 0)
792 : {
793 157 : if (EINTR == errno)
794 0 : continue;
795 157 : if (EAGAIN == errno)
796 : {
797 157 : GNUNET_assert (finished);
798 157 : GNUNET_assert (0 == off);
799 157 : break;
800 : }
801 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
802 : "recv");
803 0 : do_disconnect (dh);
804 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
805 : }
806 451 : if (0 == ret)
807 : {
808 0 : GNUNET_break (0 == off);
809 0 : if (! finished)
810 0 : return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
811 0 : if (TALER_EC_NONE == ec)
812 0 : break;
813 0 : return ec;
814 : }
815 451 : off += ret;
816 1429 : more:
817 1429 : if (off < sizeof (struct GNUNET_MessageHeader))
818 451 : continue;
819 978 : msize = ntohs (hdr->size);
820 978 : if (msize < sizeof (struct GNUNET_MessageHeader))
821 : {
822 0 : GNUNET_break_op (0);
823 0 : do_disconnect (dh);
824 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
825 : }
826 978 : if (off < msize)
827 0 : continue;
828 978 : switch (ntohs (hdr->type))
829 : {
830 357 : case TALER_HELPER_CS_MT_RES_RDERIVE:
831 357 : if (msize != sizeof (struct TALER_CRYPTO_RDeriveResponse))
832 : {
833 0 : GNUNET_break_op (0);
834 0 : do_disconnect (dh);
835 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
836 : }
837 357 : if (finished)
838 : {
839 0 : GNUNET_break_op (0);
840 0 : do_disconnect (dh);
841 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
842 : }
843 : {
844 357 : const struct TALER_CRYPTO_RDeriveResponse *rdr =
845 : (const struct TALER_CRYPTO_RDeriveResponse *) buf;
846 :
847 357 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
848 : "Received %u R pair\n",
849 : wpos);
850 357 : crps[wpos] = rdr->r_pub;
851 357 : wpos++;
852 357 : if (wpos == rend)
853 : {
854 116 : if (TALER_EC_INVALID == ec)
855 116 : ec = TALER_EC_NONE;
856 116 : finished = true;
857 : }
858 357 : break;
859 : }
860 621 : case TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE:
861 621 : if (msize != sizeof (struct TALER_CRYPTO_RDeriveFailure))
862 : {
863 0 : GNUNET_break_op (0);
864 0 : do_disconnect (dh);
865 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
866 : }
867 : {
868 621 : const struct TALER_CRYPTO_RDeriveFailure *rdf =
869 : (const struct TALER_CRYPTO_RDeriveFailure *) buf;
870 :
871 621 : ec = (enum TALER_ErrorCode) (int) ntohl (rdf->ec);
872 621 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
873 : "R derivation %u failed with status %d!\n",
874 : wpos,
875 : ec);
876 621 : wpos++;
877 621 : if (wpos == rend)
878 : {
879 41 : finished = true;
880 : }
881 621 : break;
882 : }
883 0 : case TALER_HELPER_CS_MT_AVAIL:
884 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
885 : "Received new key!\n");
886 0 : if (GNUNET_OK !=
887 0 : handle_mt_avail (dh,
888 : hdr))
889 : {
890 0 : GNUNET_break_op (0);
891 0 : do_disconnect (dh);
892 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
893 : }
894 0 : break; /* while(1) loop ensures we recvfrom() again */
895 0 : case TALER_HELPER_CS_MT_PURGE:
896 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
897 : "Received revocation!\n");
898 0 : if (GNUNET_OK !=
899 0 : handle_mt_purge (dh,
900 : hdr))
901 : {
902 0 : GNUNET_break_op (0);
903 0 : do_disconnect (dh);
904 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
905 : }
906 0 : break; /* while(1) loop ensures we recvfrom() again */
907 0 : case TALER_HELPER_CS_SYNCED:
908 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
909 : "Synchronized add odd time with CS helper!\n");
910 0 : dh->synced = true;
911 0 : break;
912 0 : default:
913 0 : GNUNET_break_op (0);
914 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
915 : "Received unexpected message of type %u\n",
916 : ntohs (hdr->type));
917 0 : do_disconnect (dh);
918 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
919 : }
920 978 : memmove (buf,
921 978 : &buf[msize],
922 : off - msize);
923 978 : off -= msize;
924 978 : goto more;
925 : } /* while(1) */
926 : } /* scope */
927 : } /* while (rpos < cdrs_length) */
928 157 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
929 : "Existing with %u signatures and status %d\n",
930 : wpos,
931 : ec);
932 157 : return ec;
933 : }
934 :
935 :
936 : void
937 27 : TALER_CRYPTO_helper_cs_disconnect (
938 : struct TALER_CRYPTO_CsDenominationHelper *dh)
939 : {
940 27 : if (-1 != dh->sock)
941 26 : do_disconnect (dh);
942 27 : GNUNET_free (dh);
943 27 : }
944 :
945 :
946 : /* end of crypto_helper_cs.c */
|