Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2020, 2021 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_util.h"
23 : #include "taler_signatures.h"
24 : #include "taler-exchange-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 9 : do_disconnect (struct TALER_CRYPTO_CsDenominationHelper *dh)
67 : {
68 9 : GNUNET_break (0 == close (dh->sock));
69 9 : dh->sock = -1;
70 9 : dh->synced = false;
71 9 : }
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 960 : try_connect (struct TALER_CRYPTO_CsDenominationHelper *dh)
83 : {
84 960 : if (-1 != dh->sock)
85 951 : return GNUNET_OK;
86 9 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
87 : "Establishing connection!\n");
88 9 : dh->sock = socket (AF_UNIX,
89 : SOCK_STREAM,
90 : 0);
91 9 : if (-1 == dh->sock)
92 : {
93 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
94 : "socket");
95 0 : return GNUNET_SYSERR;
96 : }
97 9 : if (0 !=
98 9 : connect (dh->sock,
99 9 : (const struct sockaddr *) &dh->sa,
100 : sizeof (dh->sa)))
101 : {
102 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
103 : "connect",
104 : dh->sa.sun_path);
105 0 : do_disconnect (dh);
106 0 : return GNUNET_SYSERR;
107 : }
108 9 : TALER_CRYPTO_helper_cs_poll (dh);
109 9 : return GNUNET_OK;
110 : }
111 :
112 :
113 : struct TALER_CRYPTO_CsDenominationHelper *
114 9 : TALER_CRYPTO_helper_cs_connect (
115 : const struct GNUNET_CONFIGURATION_Handle *cfg,
116 : TALER_CRYPTO_CsDenominationKeyStatusCallback dkc,
117 : void *dkc_cls)
118 : {
119 : struct TALER_CRYPTO_CsDenominationHelper *dh;
120 : char *unixpath;
121 :
122 9 : if (GNUNET_OK !=
123 9 : GNUNET_CONFIGURATION_get_value_filename (cfg,
124 : "taler-exchange-secmod-cs",
125 : "UNIXPATH",
126 : &unixpath))
127 : {
128 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
129 : "taler-exchange-secmod-cs",
130 : "UNIXPATH");
131 0 : return NULL;
132 : }
133 : /* we use >= here because we want the sun_path to always
134 : be 0-terminated */
135 9 : if (strlen (unixpath) >= sizeof (dh->sa.sun_path))
136 : {
137 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
138 : "taler-exchange-secmod-cs",
139 : "UNIXPATH",
140 : "path too long");
141 0 : GNUNET_free (unixpath);
142 0 : return NULL;
143 : }
144 9 : dh = GNUNET_new (struct TALER_CRYPTO_CsDenominationHelper);
145 9 : dh->dkc = dkc;
146 9 : dh->dkc_cls = dkc_cls;
147 9 : dh->sa.sun_family = AF_UNIX;
148 9 : strncpy (dh->sa.sun_path,
149 : unixpath,
150 : sizeof (dh->sa.sun_path) - 1);
151 9 : GNUNET_free (unixpath);
152 9 : dh->sock = -1;
153 9 : if (GNUNET_OK !=
154 9 : try_connect (dh))
155 : {
156 0 : TALER_CRYPTO_helper_cs_disconnect (dh);
157 0 : return NULL;
158 : }
159 9 : return dh;
160 : }
161 :
162 :
163 : /**
164 : * Handle a #TALER_HELPER_CS_MT_AVAIL message from the helper.
165 : *
166 : * @param dh helper context
167 : * @param hdr message that we received
168 : * @return #GNUNET_OK on success
169 : */
170 : static enum GNUNET_GenericReturnValue
171 81 : handle_mt_avail (struct TALER_CRYPTO_CsDenominationHelper *dh,
172 : const struct GNUNET_MessageHeader *hdr)
173 : {
174 81 : const struct TALER_CRYPTO_CsKeyAvailableNotification *kan
175 : = (const struct TALER_CRYPTO_CsKeyAvailableNotification *) hdr;
176 81 : const char *buf = (const char *) &kan[1];
177 : const char *section_name;
178 : uint16_t snl;
179 :
180 81 : if (sizeof (*kan) > ntohs (hdr->size))
181 : {
182 0 : GNUNET_break_op (0);
183 0 : return GNUNET_SYSERR;
184 : }
185 81 : snl = ntohs (kan->section_name_len);
186 81 : if (ntohs (hdr->size) != sizeof (*kan) + snl)
187 : {
188 0 : GNUNET_break_op (0);
189 0 : return GNUNET_SYSERR;
190 : }
191 81 : if (0 == snl)
192 : {
193 0 : GNUNET_break_op (0);
194 0 : return GNUNET_SYSERR;
195 : }
196 81 : section_name = buf;
197 81 : if ('\0' != section_name[snl - 1])
198 : {
199 0 : GNUNET_break_op (0);
200 0 : return GNUNET_SYSERR;
201 : }
202 :
203 : {
204 : struct TALER_DenominationPublicKey denom_pub;
205 : struct TALER_CsPubHashP h_cs;
206 :
207 81 : denom_pub.cipher = TALER_DENOMINATION_CS;
208 81 : denom_pub.details.cs_public_key = kan->denom_pub;
209 :
210 81 : TALER_cs_pub_hash (&denom_pub.details.cs_public_key, &h_cs);
211 81 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
212 : "Received CS key %s (%s)\n",
213 : GNUNET_h2s (&h_cs.hash),
214 : section_name);
215 81 : if (GNUNET_OK !=
216 81 : TALER_exchange_secmod_cs_verify (
217 : &h_cs,
218 : section_name,
219 : GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
220 : GNUNET_TIME_relative_ntoh (kan->duration_withdraw),
221 : &kan->secm_pub,
222 : &kan->secm_sig))
223 : {
224 0 : GNUNET_break_op (0);
225 0 : TALER_denom_pub_free (&denom_pub);
226 0 : return GNUNET_SYSERR;
227 : }
228 81 : dh->dkc (dh->dkc_cls,
229 : section_name,
230 : GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
231 : GNUNET_TIME_relative_ntoh (kan->duration_withdraw),
232 : &h_cs,
233 : &denom_pub,
234 : &kan->secm_pub,
235 : &kan->secm_sig);
236 81 : TALER_denom_pub_free (&denom_pub);
237 : }
238 81 : return GNUNET_OK;
239 : }
240 :
241 :
242 : /**
243 : * Handle a #TALER_HELPER_CS_MT_PURGE message from the helper.
244 : *
245 : * @param dh helper context
246 : * @param hdr message that we received
247 : * @return #GNUNET_OK on success
248 : */
249 : static enum GNUNET_GenericReturnValue
250 3 : handle_mt_purge (struct TALER_CRYPTO_CsDenominationHelper *dh,
251 : const struct GNUNET_MessageHeader *hdr)
252 : {
253 3 : const struct TALER_CRYPTO_CsKeyPurgeNotification *pn
254 : = (const struct TALER_CRYPTO_CsKeyPurgeNotification *) hdr;
255 :
256 3 : if (sizeof (*pn) != ntohs (hdr->size))
257 : {
258 0 : GNUNET_break_op (0);
259 0 : return GNUNET_SYSERR;
260 : }
261 3 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
262 : "Received revocation of denomination key %s\n",
263 : GNUNET_h2s (&pn->h_cs.hash));
264 3 : dh->dkc (dh->dkc_cls,
265 : NULL,
266 3 : GNUNET_TIME_UNIT_ZERO_TS,
267 3 : GNUNET_TIME_UNIT_ZERO,
268 : &pn->h_cs,
269 : NULL,
270 : NULL,
271 : NULL);
272 3 : return GNUNET_OK;
273 : }
274 :
275 :
276 : void
277 24 : TALER_CRYPTO_helper_cs_poll (struct TALER_CRYPTO_CsDenominationHelper *dh)
278 : {
279 : char buf[UINT16_MAX];
280 24 : size_t off = 0;
281 24 : unsigned int retry_limit = 3;
282 24 : const struct GNUNET_MessageHeader *hdr
283 : = (const struct GNUNET_MessageHeader *) buf;
284 :
285 24 : if (GNUNET_OK !=
286 24 : try_connect (dh))
287 0 : return; /* give up */
288 : while (1)
289 12 : {
290 : uint16_t msize;
291 : ssize_t ret;
292 :
293 36 : ret = recv (dh->sock,
294 : buf + off,
295 : sizeof (buf) - off,
296 36 : (dh->synced && (0 == off))
297 : ? MSG_DONTWAIT
298 : : 0);
299 36 : if (ret < 0)
300 : {
301 24 : if (EINTR == errno)
302 0 : continue;
303 24 : if (EAGAIN == errno)
304 : {
305 24 : GNUNET_assert (dh->synced);
306 24 : GNUNET_assert (0 == off);
307 24 : break;
308 : }
309 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
310 : "recv");
311 0 : do_disconnect (dh);
312 0 : if (0 == retry_limit)
313 0 : return; /* give up */
314 0 : if (GNUNET_OK !=
315 0 : try_connect (dh))
316 0 : return; /* give up */
317 0 : retry_limit--;
318 0 : continue;
319 : }
320 12 : if (0 == ret)
321 : {
322 0 : GNUNET_break (0 == off);
323 0 : return;
324 : }
325 12 : off += ret;
326 105 : more:
327 105 : if (off < sizeof (struct GNUNET_MessageHeader))
328 12 : continue;
329 93 : msize = ntohs (hdr->size);
330 93 : if (off < msize)
331 0 : continue;
332 93 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
333 : "Received message of type %u and length %u\n",
334 : (unsigned int) ntohs (hdr->type),
335 : (unsigned int) msize);
336 93 : switch (ntohs (hdr->type))
337 : {
338 81 : case TALER_HELPER_CS_MT_AVAIL:
339 81 : if (GNUNET_OK !=
340 81 : handle_mt_avail (dh,
341 : hdr))
342 : {
343 0 : GNUNET_break_op (0);
344 0 : do_disconnect (dh);
345 0 : return;
346 : }
347 81 : break;
348 3 : case TALER_HELPER_CS_MT_PURGE:
349 3 : if (GNUNET_OK !=
350 3 : handle_mt_purge (dh,
351 : hdr))
352 : {
353 0 : GNUNET_break_op (0);
354 0 : do_disconnect (dh);
355 0 : return;
356 : }
357 3 : break;
358 9 : case TALER_HELPER_CS_SYNCED:
359 9 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
360 : "Now synchronized with CS helper\n");
361 9 : dh->synced = true;
362 9 : break;
363 0 : default:
364 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
365 : "Received unexpected message of type %d (len: %u)\n",
366 : (unsigned int) ntohs (hdr->type),
367 : (unsigned int) msize);
368 0 : GNUNET_break_op (0);
369 0 : do_disconnect (dh);
370 0 : return;
371 : }
372 93 : memmove (buf,
373 93 : &buf[msize],
374 : off - msize);
375 93 : off -= msize;
376 93 : goto more;
377 : }
378 : }
379 :
380 :
381 : /**
382 : * Request helper @a dh to sign @a msg using the public key corresponding to
383 : * @a h_denom_pub.
384 : *
385 : * This operation will block until the signature has been obtained. Should
386 : * this process receive a signal (that is not ignored) while the operation is
387 : * pending, the operation will fail. Note that the helper may still believe
388 : * that it created the signature. Thus, signals may result in a small
389 : * differences in the signature counters. Retrying in this case may work.
390 : *
391 : * @param dh helper process connection
392 : * @param h_cs hash of the CS public key to use to sign
393 : * @param blinded_planchet blinded planchet containing c and nonce
394 : * @param for_melt true if the HKDF for melt should be used
395 : * @param[out] bs set to the blind signature
396 : * @return #TALER_EC_NONE on success
397 : */
398 : static enum TALER_ErrorCode
399 902 : helper_cs_sign (
400 : struct TALER_CRYPTO_CsDenominationHelper *dh,
401 : const struct TALER_CsPubHashP *h_cs,
402 : const struct TALER_BlindedCsPlanchet *blinded_planchet,
403 : bool for_melt,
404 : struct TALER_BlindedDenominationSignature *bs)
405 : {
406 902 : enum TALER_ErrorCode ec = TALER_EC_INVALID;
407 :
408 902 : bs->cipher = TALER_DENOMINATION_INVALID;
409 902 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
410 : "Starting signature process\n");
411 902 : if (GNUNET_OK !=
412 902 : try_connect (dh))
413 : {
414 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
415 : "Failed to connect to helper\n");
416 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
417 : }
418 :
419 902 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
420 : "Requesting signature\n");
421 : {
422 : char buf[sizeof (struct TALER_CRYPTO_CsSignRequest)];
423 902 : struct TALER_CRYPTO_CsSignRequest *sr
424 : = (struct TALER_CRYPTO_CsSignRequest *) buf;
425 :
426 902 : sr->header.size = htons (sizeof (buf));
427 902 : sr->header.type = htons (TALER_HELPER_CS_MT_REQ_SIGN);
428 902 : sr->for_melt = htonl (for_melt ? 1 : 0);
429 902 : sr->h_cs = *h_cs;
430 902 : sr->planchet = *blinded_planchet;
431 902 : if (GNUNET_OK !=
432 902 : TALER_crypto_helper_send_all (dh->sock,
433 : buf,
434 : sizeof (buf)))
435 : {
436 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
437 : "send");
438 0 : do_disconnect (dh);
439 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
440 : }
441 : }
442 :
443 902 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
444 : "Awaiting reply\n");
445 : {
446 : char buf[UINT16_MAX];
447 902 : size_t off = 0;
448 902 : const struct GNUNET_MessageHeader *hdr
449 : = (const struct GNUNET_MessageHeader *) buf;
450 902 : bool finished = false;
451 :
452 : while (1)
453 902 : {
454 : uint16_t msize;
455 : ssize_t ret;
456 :
457 2706 : ret = recv (dh->sock,
458 1804 : &buf[off],
459 : sizeof (buf) - off,
460 902 : (finished && (0 == off))
461 : ? MSG_DONTWAIT
462 : : 0);
463 1804 : if (ret < 0)
464 : {
465 902 : if (EINTR == errno)
466 0 : continue;
467 902 : if (EAGAIN == errno)
468 : {
469 902 : GNUNET_assert (finished);
470 902 : GNUNET_assert (0 == off);
471 902 : return ec;
472 : }
473 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
474 : "recv");
475 0 : do_disconnect (dh);
476 0 : ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
477 0 : break;
478 : }
479 902 : if (0 == ret)
480 : {
481 0 : GNUNET_break (0 == off);
482 0 : if (! finished)
483 0 : ec = TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
484 0 : return ec;
485 : }
486 902 : off += ret;
487 1804 : more:
488 1804 : if (off < sizeof (struct GNUNET_MessageHeader))
489 902 : continue;
490 902 : msize = ntohs (hdr->size);
491 902 : if (off < msize)
492 0 : continue;
493 902 : switch (ntohs (hdr->type))
494 : {
495 901 : case TALER_HELPER_CS_MT_RES_SIGNATURE:
496 901 : if (msize < sizeof (struct TALER_CRYPTO_SignResponse))
497 : {
498 0 : GNUNET_break_op (0);
499 0 : do_disconnect (dh);
500 0 : ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
501 0 : goto end;
502 : }
503 901 : if (finished)
504 : {
505 0 : GNUNET_break_op (0);
506 0 : do_disconnect (dh);
507 0 : ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
508 0 : goto end;
509 : }
510 : {
511 901 : const struct TALER_CRYPTO_SignResponse *sr =
512 : (const struct TALER_CRYPTO_SignResponse *) buf;
513 :
514 901 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
515 : "Received signature\n");
516 901 : ec = TALER_EC_NONE;
517 901 : finished = true;
518 901 : bs->cipher = TALER_DENOMINATION_CS;
519 901 : bs->details.blinded_cs_answer = sr->cs_answer;
520 901 : break;
521 : }
522 1 : case TALER_HELPER_CS_MT_RES_SIGN_FAILURE:
523 1 : if (msize != sizeof (struct TALER_CRYPTO_SignFailure))
524 : {
525 0 : GNUNET_break_op (0);
526 0 : do_disconnect (dh);
527 0 : ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
528 0 : goto end;
529 : }
530 : {
531 1 : const struct TALER_CRYPTO_SignFailure *sf =
532 : (const struct TALER_CRYPTO_SignFailure *) buf;
533 :
534 1 : ec = (enum TALER_ErrorCode) ntohl (sf->ec);
535 1 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
536 : "Signing failed!\n");
537 1 : finished = true;
538 1 : break;
539 : }
540 0 : case TALER_HELPER_CS_MT_AVAIL:
541 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
542 : "Received new key!\n");
543 0 : if (GNUNET_OK !=
544 0 : handle_mt_avail (dh,
545 : hdr))
546 : {
547 0 : GNUNET_break_op (0);
548 0 : do_disconnect (dh);
549 0 : ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
550 0 : goto end;
551 : }
552 0 : break; /* while(1) loop ensures we recvfrom() again */
553 0 : case TALER_HELPER_CS_MT_PURGE:
554 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
555 : "Received revocation!\n");
556 0 : if (GNUNET_OK !=
557 0 : handle_mt_purge (dh,
558 : hdr))
559 : {
560 0 : GNUNET_break_op (0);
561 0 : do_disconnect (dh);
562 0 : ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
563 0 : goto end;
564 : }
565 0 : break; /* while(1) loop ensures we recvfrom() again */
566 0 : case TALER_HELPER_CS_SYNCED:
567 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
568 : "Synchronized add odd time with CS helper!\n");
569 0 : dh->synced = true;
570 0 : break;
571 0 : default:
572 0 : GNUNET_break_op (0);
573 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
574 : "Received unexpected message of type %u\n",
575 : ntohs (hdr->type));
576 0 : do_disconnect (dh);
577 0 : ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
578 0 : goto end;
579 : }
580 902 : memmove (buf,
581 902 : &buf[msize],
582 : off - msize);
583 902 : off -= msize;
584 902 : goto more;
585 : } /* while(1) */
586 0 : end:
587 0 : if (finished)
588 0 : TALER_blinded_denom_sig_free (bs);
589 0 : return ec;
590 : }
591 : }
592 :
593 :
594 : enum TALER_ErrorCode
595 900 : TALER_CRYPTO_helper_cs_sign_melt (
596 : struct TALER_CRYPTO_CsDenominationHelper *dh,
597 : const struct TALER_CsPubHashP *h_cs,
598 : const struct TALER_BlindedCsPlanchet *blinded_planchet,
599 : struct TALER_BlindedDenominationSignature *bs)
600 : {
601 900 : return helper_cs_sign (dh,
602 : h_cs,
603 : blinded_planchet,
604 : true,
605 : bs);
606 : }
607 :
608 :
609 : enum TALER_ErrorCode
610 2 : TALER_CRYPTO_helper_cs_sign_withdraw (
611 : struct TALER_CRYPTO_CsDenominationHelper *dh,
612 : const struct TALER_CsPubHashP *h_cs,
613 : const struct TALER_BlindedCsPlanchet *blinded_planchet,
614 : struct TALER_BlindedDenominationSignature *bs)
615 : {
616 2 : return helper_cs_sign (dh,
617 : h_cs,
618 : blinded_planchet,
619 : false,
620 : bs);
621 : }
622 :
623 :
624 : void
625 3 : TALER_CRYPTO_helper_cs_revoke (
626 : struct TALER_CRYPTO_CsDenominationHelper *dh,
627 : const struct TALER_CsPubHashP *h_cs)
628 : {
629 3 : struct TALER_CRYPTO_CsRevokeRequest rr = {
630 3 : .header.size = htons (sizeof (rr)),
631 3 : .header.type = htons (TALER_HELPER_CS_MT_REQ_REVOKE),
632 : .h_cs = *h_cs
633 : };
634 :
635 3 : if (GNUNET_OK !=
636 3 : try_connect (dh))
637 0 : return; /* give up */
638 3 : if (GNUNET_OK !=
639 3 : TALER_crypto_helper_send_all (dh->sock,
640 : &rr,
641 : sizeof (rr)))
642 : {
643 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
644 : "send");
645 0 : do_disconnect (dh);
646 0 : return;
647 : }
648 3 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
649 : "Requested revocation of denomination key %s\n",
650 : GNUNET_h2s (&h_cs->hash));
651 : }
652 :
653 :
654 : /**
655 : * Ask the helper to derive R using the @a nonce and denomination key
656 : * associated with @a h_cs.
657 : *
658 : * This operation will block until the R has been obtained. Should
659 : * this process receive a signal (that is not ignored) while the operation is
660 : * pending, the operation will fail. Note that the helper may still believe
661 : * that it created the signature. Thus, signals may result in a small
662 : * differences in the signature counters. Retrying in this case may work.
663 : *
664 : * @param dh helper to process connection
665 : * @param h_cs hash of the CS public key to revoke
666 : * @param nonce witdhraw nonce
667 : * @param for_melt true if the HKDF for melt should be used
668 : * @param[out] crp set to the pair of R values
669 : * @return set to the error code (or #TALER_EC_NONE on success)
670 : */
671 : static enum TALER_ErrorCode
672 22 : helper_cs_r_derive (struct TALER_CRYPTO_CsDenominationHelper *dh,
673 : const struct TALER_CsPubHashP *h_cs,
674 : const struct TALER_CsNonce *nonce,
675 : bool for_melt,
676 : struct TALER_DenominationCSPublicRPairP *crp)
677 : {
678 22 : enum TALER_ErrorCode ec = TALER_EC_INVALID;
679 :
680 22 : memset (crp,
681 : 0,
682 : sizeof (*crp));
683 22 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
684 : "Starting R derivation process\n");
685 22 : if (GNUNET_OK !=
686 22 : try_connect (dh))
687 : {
688 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
689 : "Failed to connect to helper\n");
690 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
691 : }
692 :
693 22 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
694 : "Requesting R\n");
695 : {
696 22 : struct TALER_CRYPTO_CsRDeriveRequest rdr = {
697 22 : .header.size = htons (sizeof (rdr)),
698 22 : .header.type = htons (TALER_HELPER_CS_MT_REQ_RDERIVE),
699 22 : .for_melt = htonl (for_melt ? 1 : 0),
700 : .h_cs = *h_cs,
701 : .nonce = *nonce
702 : };
703 :
704 22 : if (GNUNET_OK !=
705 22 : TALER_crypto_helper_send_all (dh->sock,
706 : &rdr,
707 : sizeof (rdr)))
708 : {
709 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
710 : "send");
711 0 : do_disconnect (dh);
712 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
713 : }
714 : }
715 :
716 22 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
717 : "Awaiting reply\n");
718 : {
719 : char buf[UINT16_MAX];
720 22 : size_t off = 0;
721 22 : const struct GNUNET_MessageHeader *hdr
722 : = (const struct GNUNET_MessageHeader *) buf;
723 22 : bool finished = false;
724 :
725 : while (1)
726 22 : {
727 : uint16_t msize;
728 : ssize_t ret;
729 :
730 66 : ret = recv (dh->sock,
731 44 : &buf[off],
732 : sizeof (buf) - off,
733 22 : (finished && (0 == off))
734 : ? MSG_DONTWAIT
735 : : 0);
736 44 : if (ret < 0)
737 : {
738 22 : if (EINTR == errno)
739 0 : continue;
740 22 : if (EAGAIN == errno)
741 : {
742 22 : GNUNET_assert (finished);
743 22 : GNUNET_assert (0 == off);
744 22 : return ec;
745 : }
746 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
747 : "recv");
748 0 : do_disconnect (dh);
749 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
750 : }
751 22 : if (0 == ret)
752 : {
753 0 : GNUNET_break (0 == off);
754 0 : if (! finished)
755 0 : return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
756 0 : return ec;
757 : }
758 22 : off += ret;
759 44 : more:
760 44 : if (off < sizeof (struct GNUNET_MessageHeader))
761 22 : continue;
762 22 : msize = ntohs (hdr->size);
763 22 : if (off < msize)
764 0 : continue;
765 22 : switch (ntohs (hdr->type))
766 : {
767 11 : case TALER_HELPER_CS_MT_RES_RDERIVE:
768 11 : if (msize != sizeof (struct TALER_CRYPTO_RDeriveResponse))
769 : {
770 0 : GNUNET_break_op (0);
771 0 : do_disconnect (dh);
772 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
773 : }
774 11 : if (finished)
775 : {
776 0 : GNUNET_break_op (0);
777 0 : do_disconnect (dh);
778 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
779 : }
780 : {
781 11 : const struct TALER_CRYPTO_RDeriveResponse *rdr =
782 : (const struct TALER_CRYPTO_RDeriveResponse *) buf;
783 :
784 11 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
785 : "Received R\n");
786 11 : finished = true;
787 11 : ec = TALER_EC_NONE;
788 11 : *crp = rdr->r_pub;
789 11 : break;
790 : }
791 11 : case TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE:
792 11 : if (msize != sizeof (struct TALER_CRYPTO_RDeriveFailure))
793 : {
794 0 : GNUNET_break_op (0);
795 0 : do_disconnect (dh);
796 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
797 : }
798 : {
799 11 : const struct TALER_CRYPTO_RDeriveFailure *rdf =
800 : (const struct TALER_CRYPTO_RDeriveFailure *) buf;
801 :
802 11 : ec = (enum TALER_ErrorCode) ntohl (rdf->ec);
803 11 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
804 : "R derivation failed!\n");
805 11 : finished = true;
806 11 : break;
807 : }
808 0 : case TALER_HELPER_CS_MT_AVAIL:
809 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
810 : "Received new key!\n");
811 0 : if (GNUNET_OK !=
812 0 : handle_mt_avail (dh,
813 : hdr))
814 : {
815 0 : GNUNET_break_op (0);
816 0 : do_disconnect (dh);
817 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
818 : }
819 0 : break; /* while(1) loop ensures we recvfrom() again */
820 0 : case TALER_HELPER_CS_MT_PURGE:
821 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
822 : "Received revocation!\n");
823 0 : if (GNUNET_OK !=
824 0 : handle_mt_purge (dh,
825 : hdr))
826 : {
827 0 : GNUNET_break_op (0);
828 0 : do_disconnect (dh);
829 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
830 : }
831 0 : break; /* while(1) loop ensures we recvfrom() again */
832 0 : case TALER_HELPER_CS_SYNCED:
833 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
834 : "Synchronized add odd time with CS helper!\n");
835 0 : dh->synced = true;
836 0 : break;
837 0 : default:
838 0 : GNUNET_break_op (0);
839 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
840 : "Received unexpected message of type %u\n",
841 : ntohs (hdr->type));
842 0 : do_disconnect (dh);
843 0 : return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
844 : }
845 22 : memmove (buf,
846 22 : &buf[msize],
847 : off - msize);
848 22 : off -= msize;
849 22 : goto more;
850 : } /* while(1) */
851 : }
852 : }
853 :
854 :
855 : enum TALER_ErrorCode
856 13 : TALER_CRYPTO_helper_cs_r_derive_withdraw (
857 : struct TALER_CRYPTO_CsDenominationHelper *dh,
858 : const struct TALER_CsPubHashP *h_cs,
859 : const struct TALER_CsNonce *nonce,
860 : struct TALER_DenominationCSPublicRPairP *crp)
861 : {
862 13 : return helper_cs_r_derive (dh,
863 : h_cs,
864 : nonce,
865 : false,
866 : crp);
867 : }
868 :
869 :
870 : enum TALER_ErrorCode
871 9 : TALER_CRYPTO_helper_cs_r_derive_melt (
872 : struct TALER_CRYPTO_CsDenominationHelper *dh,
873 : const struct TALER_CsPubHashP *h_cs,
874 : const struct TALER_CsNonce *nonce,
875 : struct TALER_DenominationCSPublicRPairP *crp)
876 : {
877 9 : return helper_cs_r_derive (dh,
878 : h_cs,
879 : nonce,
880 : true,
881 : crp);
882 : }
883 :
884 :
885 : void
886 9 : TALER_CRYPTO_helper_cs_disconnect (
887 : struct TALER_CRYPTO_CsDenominationHelper *dh)
888 : {
889 9 : if (-1 != dh->sock)
890 9 : do_disconnect (dh);
891 9 : GNUNET_free (dh);
892 9 : }
893 :
894 :
895 : /* end of crypto_helper_cs.c */
|