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_esign.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-eddsa.h"
25 : #include <poll.h>
26 : #include "crypto_helper_common.h"
27 :
28 :
29 : struct TALER_CRYPTO_ExchangeSignHelper
30 : {
31 : /**
32 : * Function to call with updates to available key material.
33 : */
34 : TALER_CRYPTO_ExchangeKeyStatusCallback ekc;
35 :
36 : /**
37 : * Closure for @e ekc
38 : */
39 : void *ekc_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 reached the sync'ed state?
54 : */
55 : bool synced;
56 :
57 : };
58 :
59 :
60 : /**
61 : * Disconnect from the helper process. Updates
62 : * @e sock field in @a esh.
63 : *
64 : * @param[in,out] esh handle to tear down connection of
65 : */
66 : static void
67 9 : do_disconnect (struct TALER_CRYPTO_ExchangeSignHelper *esh)
68 : {
69 9 : GNUNET_break (0 == close (esh->sock));
70 9 : esh->sock = -1;
71 9 : esh->synced = false;
72 9 : }
73 :
74 :
75 : /**
76 : * Try to connect to the helper process. Updates
77 : * @e sock field in @a esh.
78 : *
79 : * @param[in,out] esh handle to establish connection for
80 : * @return #GNUNET_OK on success
81 : */
82 : static enum GNUNET_GenericReturnValue
83 1830 : try_connect (struct TALER_CRYPTO_ExchangeSignHelper *esh)
84 : {
85 1830 : if (-1 != esh->sock)
86 1821 : return GNUNET_OK;
87 9 : esh->sock = socket (AF_UNIX,
88 : SOCK_STREAM,
89 : 0);
90 9 : if (-1 == esh->sock)
91 : {
92 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
93 : "socket");
94 0 : return GNUNET_SYSERR;
95 : }
96 9 : if (0 !=
97 9 : connect (esh->sock,
98 9 : (const struct sockaddr *) &esh->sa,
99 : sizeof (esh->sa)))
100 : {
101 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
102 : "connect",
103 : esh->sa.sun_path);
104 0 : do_disconnect (esh);
105 0 : return GNUNET_SYSERR;
106 : }
107 9 : return GNUNET_OK;
108 : }
109 :
110 :
111 : struct TALER_CRYPTO_ExchangeSignHelper *
112 9 : TALER_CRYPTO_helper_esign_connect (
113 : const struct GNUNET_CONFIGURATION_Handle *cfg,
114 : TALER_CRYPTO_ExchangeKeyStatusCallback ekc,
115 : void *ekc_cls)
116 : {
117 : struct TALER_CRYPTO_ExchangeSignHelper *esh;
118 : char *unixpath;
119 :
120 9 : if (GNUNET_OK !=
121 9 : GNUNET_CONFIGURATION_get_value_filename (cfg,
122 : "taler-exchange-secmod-eddsa",
123 : "UNIXPATH",
124 : &unixpath))
125 : {
126 0 : GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
127 : "taler-exchange-secmod-eddsa",
128 : "UNIXPATH");
129 0 : return NULL;
130 : }
131 : /* we use >= here because we want the sun_path to always
132 : be 0-terminated */
133 9 : if (strlen (unixpath) >= sizeof (esh->sa.sun_path))
134 : {
135 0 : GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
136 : "taler-exchange-secmod-eddsa",
137 : "UNIXPATH",
138 : "path too long");
139 0 : GNUNET_free (unixpath);
140 0 : return NULL;
141 : }
142 9 : esh = GNUNET_new (struct TALER_CRYPTO_ExchangeSignHelper);
143 9 : esh->ekc = ekc;
144 9 : esh->ekc_cls = ekc_cls;
145 9 : esh->sa.sun_family = AF_UNIX;
146 9 : strncpy (esh->sa.sun_path,
147 : unixpath,
148 : sizeof (esh->sa.sun_path) - 1);
149 9 : GNUNET_free (unixpath);
150 9 : esh->sock = -1;
151 9 : if (GNUNET_OK !=
152 9 : try_connect (esh))
153 : {
154 0 : TALER_CRYPTO_helper_esign_disconnect (esh);
155 0 : return NULL;
156 : }
157 :
158 9 : TALER_CRYPTO_helper_esign_poll (esh);
159 9 : return esh;
160 : }
161 :
162 :
163 : /**
164 : * Handle a #TALER_HELPER_EDDSA_MT_AVAIL message from the helper.
165 : *
166 : * @param esh 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_ExchangeSignHelper *esh,
172 : const struct GNUNET_MessageHeader *hdr)
173 : {
174 81 : const struct TALER_CRYPTO_EddsaKeyAvailableNotification *kan
175 : = (const struct TALER_CRYPTO_EddsaKeyAvailableNotification *) hdr;
176 :
177 81 : if (sizeof (*kan) != ntohs (hdr->size))
178 : {
179 0 : GNUNET_break_op (0);
180 0 : return GNUNET_SYSERR;
181 : }
182 81 : if (GNUNET_OK !=
183 81 : TALER_exchange_secmod_eddsa_verify (
184 : &kan->exchange_pub,
185 : GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
186 : GNUNET_TIME_relative_ntoh (kan->duration),
187 : &kan->secm_pub,
188 : &kan->secm_sig))
189 : {
190 0 : GNUNET_break_op (0);
191 0 : return GNUNET_SYSERR;
192 : }
193 81 : esh->ekc (esh->ekc_cls,
194 : GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
195 : GNUNET_TIME_relative_ntoh (kan->duration),
196 : &kan->exchange_pub,
197 : &kan->secm_pub,
198 : &kan->secm_sig);
199 81 : return GNUNET_OK;
200 : }
201 :
202 :
203 : /**
204 : * Handle a #TALER_HELPER_EDDSA_MT_PURGE message from the helper.
205 : *
206 : * @param esh helper context
207 : * @param hdr message that we received
208 : * @return #GNUNET_OK on success
209 : */
210 : static enum GNUNET_GenericReturnValue
211 3 : handle_mt_purge (struct TALER_CRYPTO_ExchangeSignHelper *esh,
212 : const struct GNUNET_MessageHeader *hdr)
213 : {
214 3 : const struct TALER_CRYPTO_EddsaKeyPurgeNotification *pn
215 : = (const struct TALER_CRYPTO_EddsaKeyPurgeNotification *) hdr;
216 :
217 3 : if (sizeof (*pn) != ntohs (hdr->size))
218 : {
219 0 : GNUNET_break_op (0);
220 0 : return GNUNET_SYSERR;
221 : }
222 3 : esh->ekc (esh->ekc_cls,
223 3 : GNUNET_TIME_UNIT_ZERO_TS,
224 3 : GNUNET_TIME_UNIT_ZERO,
225 : &pn->exchange_pub,
226 : NULL,
227 : NULL);
228 3 : return GNUNET_OK;
229 : }
230 :
231 :
232 : void
233 915 : TALER_CRYPTO_helper_esign_poll (struct TALER_CRYPTO_ExchangeSignHelper *esh)
234 : {
235 : char buf[UINT16_MAX];
236 915 : size_t off = 0;
237 915 : unsigned int retry_limit = 3;
238 915 : const struct GNUNET_MessageHeader *hdr
239 : = (const struct GNUNET_MessageHeader *) buf;
240 :
241 915 : if (GNUNET_OK !=
242 915 : try_connect (esh))
243 0 : return; /* give up */
244 : while (1)
245 51 : {
246 : uint16_t msize;
247 : ssize_t ret;
248 :
249 966 : ret = recv (esh->sock,
250 : buf + off,
251 : sizeof (buf) - off,
252 966 : (esh->synced && (0 == off))
253 : ? MSG_DONTWAIT
254 : : 0);
255 966 : if (ret < 0)
256 : {
257 915 : if (EINTR == errno)
258 0 : continue;
259 915 : if (EAGAIN == errno)
260 : {
261 915 : GNUNET_assert (esh->synced);
262 915 : GNUNET_assert (0 == off);
263 915 : break;
264 : }
265 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
266 : "recv");
267 0 : do_disconnect (esh);
268 0 : if (0 == retry_limit)
269 0 : return; /* give up */
270 0 : if (GNUNET_OK !=
271 0 : try_connect (esh))
272 0 : return; /* give up */
273 0 : retry_limit--;
274 0 : continue;
275 : }
276 51 : if (0 == ret)
277 : {
278 0 : GNUNET_break (0 == off);
279 0 : return;
280 : }
281 51 : off += ret;
282 144 : more:
283 144 : if (off < sizeof (struct GNUNET_MessageHeader))
284 51 : continue;
285 93 : msize = ntohs (hdr->size);
286 93 : if (off < msize)
287 0 : continue;
288 93 : switch (ntohs (hdr->type))
289 : {
290 81 : case TALER_HELPER_EDDSA_MT_AVAIL:
291 81 : if (GNUNET_OK !=
292 81 : handle_mt_avail (esh,
293 : hdr))
294 : {
295 0 : GNUNET_break_op (0);
296 0 : do_disconnect (esh);
297 0 : return;
298 : }
299 81 : break;
300 3 : case TALER_HELPER_EDDSA_MT_PURGE:
301 3 : if (GNUNET_OK !=
302 3 : handle_mt_purge (esh,
303 : hdr))
304 : {
305 0 : GNUNET_break_op (0);
306 0 : do_disconnect (esh);
307 0 : return;
308 : }
309 3 : break;
310 9 : case TALER_HELPER_EDDSA_SYNCED:
311 9 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
312 : "Now synchronized with EdDSA helper\n");
313 9 : esh->synced = true;
314 9 : break;
315 0 : default:
316 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
317 : "Received unexpected message of type %d (len: %u)\n",
318 : (unsigned int) ntohs (hdr->type),
319 : (unsigned int) msize);
320 0 : GNUNET_break_op (0);
321 0 : do_disconnect (esh);
322 0 : return;
323 : }
324 93 : memmove (buf,
325 93 : &buf[msize],
326 : off - msize);
327 93 : off -= msize;
328 93 : goto more;
329 : }
330 : }
331 :
332 :
333 : enum TALER_ErrorCode
334 903 : TALER_CRYPTO_helper_esign_sign_ (
335 : struct TALER_CRYPTO_ExchangeSignHelper *esh,
336 : const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
337 : struct TALER_ExchangePublicKeyP *exchange_pub,
338 : struct TALER_ExchangeSignatureP *exchange_sig)
339 : {
340 903 : uint32_t purpose_size = ntohl (purpose->size);
341 :
342 903 : if (GNUNET_OK !=
343 903 : try_connect (esh))
344 : {
345 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
346 : "Failed to connect to helper\n");
347 0 : return TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE;
348 : }
349 903 : GNUNET_assert (purpose_size <
350 : UINT16_MAX - sizeof (struct TALER_CRYPTO_EddsaSignRequest));
351 903 : {
352 903 : char buf[sizeof (struct TALER_CRYPTO_EddsaSignRequest) + purpose_size
353 903 : - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose)];
354 903 : struct TALER_CRYPTO_EddsaSignRequest *sr
355 : = (struct TALER_CRYPTO_EddsaSignRequest *) buf;
356 :
357 903 : sr->header.size = htons (sizeof (buf));
358 903 : sr->header.type = htons (TALER_HELPER_EDDSA_MT_REQ_SIGN);
359 903 : sr->reserved = htonl (0);
360 903 : memcpy (&sr->purpose,
361 : purpose,
362 : purpose_size);
363 903 : if (GNUNET_OK !=
364 903 : TALER_crypto_helper_send_all (esh->sock,
365 : buf,
366 : sizeof (buf)))
367 : {
368 0 : GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
369 : "send",
370 : esh->sa.sun_path);
371 0 : do_disconnect (esh);
372 0 : return TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE;
373 : }
374 : }
375 :
376 : {
377 : char buf[UINT16_MAX];
378 903 : size_t off = 0;
379 903 : const struct GNUNET_MessageHeader *hdr
380 : = (const struct GNUNET_MessageHeader *) buf;
381 903 : bool finished = false;
382 903 : enum TALER_ErrorCode ec = TALER_EC_INVALID;
383 :
384 : while (1)
385 903 : {
386 : ssize_t ret;
387 : uint16_t msize;
388 :
389 2709 : ret = recv (esh->sock,
390 1806 : &buf[off],
391 : sizeof (buf) - off,
392 903 : (finished && (0 == off))
393 : ? MSG_DONTWAIT
394 : : 0);
395 1806 : if (ret < 0)
396 : {
397 903 : if (EINTR == errno)
398 0 : continue;
399 903 : if (EAGAIN == errno)
400 : {
401 903 : GNUNET_assert (finished);
402 903 : GNUNET_assert (0 == off);
403 903 : break;
404 : }
405 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
406 : "recv");
407 0 : do_disconnect (esh);
408 0 : return TALER_EC_EXCHANGE_SIGNKEY_HELPER_UNAVAILABLE;
409 : }
410 903 : if (0 == ret)
411 : {
412 0 : GNUNET_break (0 == off);
413 0 : if (finished)
414 0 : return TALER_EC_NONE;
415 0 : return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
416 : }
417 903 : off += ret;
418 1806 : more:
419 1806 : if (off < sizeof (struct GNUNET_MessageHeader))
420 903 : continue;
421 903 : msize = ntohs (hdr->size);
422 903 : if (off < msize)
423 0 : continue;
424 903 : switch (ntohs (hdr->type))
425 : {
426 903 : case TALER_HELPER_EDDSA_MT_RES_SIGNATURE:
427 903 : if (msize != sizeof (struct TALER_CRYPTO_EddsaSignResponse))
428 : {
429 0 : GNUNET_break_op (0);
430 0 : do_disconnect (esh);
431 0 : return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
432 : }
433 903 : if (finished)
434 : {
435 0 : GNUNET_break_op (0);
436 0 : do_disconnect (esh);
437 0 : return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
438 : }
439 : {
440 903 : const struct TALER_CRYPTO_EddsaSignResponse *sr =
441 : (const struct TALER_CRYPTO_EddsaSignResponse *) buf;
442 903 : *exchange_sig = sr->exchange_sig;
443 903 : *exchange_pub = sr->exchange_pub;
444 903 : finished = true;
445 903 : ec = TALER_EC_NONE;
446 903 : break;
447 : }
448 0 : case TALER_HELPER_EDDSA_MT_RES_SIGN_FAILURE:
449 0 : if (msize != sizeof (struct TALER_CRYPTO_EddsaSignFailure))
450 : {
451 0 : GNUNET_break_op (0);
452 0 : do_disconnect (esh);
453 0 : return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
454 : }
455 : {
456 0 : const struct TALER_CRYPTO_EddsaSignFailure *sf =
457 : (const struct TALER_CRYPTO_EddsaSignFailure *) buf;
458 :
459 0 : finished = true;
460 0 : ec = (enum TALER_ErrorCode) ntohl (sf->ec);
461 0 : break;
462 : }
463 0 : case TALER_HELPER_EDDSA_MT_AVAIL:
464 0 : if (GNUNET_OK !=
465 0 : handle_mt_avail (esh,
466 : hdr))
467 : {
468 0 : GNUNET_break_op (0);
469 0 : do_disconnect (esh);
470 0 : return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
471 : }
472 0 : break; /* while(1) loop ensures we recv() again */
473 0 : case TALER_HELPER_EDDSA_MT_PURGE:
474 0 : if (GNUNET_OK !=
475 0 : handle_mt_purge (esh,
476 : hdr))
477 : {
478 0 : GNUNET_break_op (0);
479 0 : do_disconnect (esh);
480 0 : return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
481 : }
482 0 : break; /* while(1) loop ensures we recv() again */
483 0 : case TALER_HELPER_EDDSA_SYNCED:
484 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
485 : "Synchronized add odd time with EdDSA helper!\n");
486 0 : esh->synced = true;
487 0 : break;
488 0 : default:
489 0 : GNUNET_break_op (0);
490 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
491 : "Received unexpected message of type %u\n",
492 : ntohs (hdr->type));
493 0 : do_disconnect (esh);
494 0 : return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
495 : }
496 903 : memmove (buf,
497 903 : &buf[msize],
498 : off - msize);
499 903 : off -= msize;
500 903 : goto more;
501 : } /* while(1) */
502 903 : return ec;
503 : }
504 : }
505 :
506 :
507 : void
508 3 : TALER_CRYPTO_helper_esign_revoke (
509 : struct TALER_CRYPTO_ExchangeSignHelper *esh,
510 : const struct TALER_ExchangePublicKeyP *exchange_pub)
511 : {
512 3 : if (GNUNET_OK !=
513 3 : try_connect (esh))
514 0 : return; /* give up */
515 : {
516 3 : struct TALER_CRYPTO_EddsaRevokeRequest rr = {
517 3 : .header.size = htons (sizeof (rr)),
518 3 : .header.type = htons (TALER_HELPER_EDDSA_MT_REQ_REVOKE),
519 : .exchange_pub = *exchange_pub
520 : };
521 :
522 3 : if (GNUNET_OK !=
523 3 : TALER_crypto_helper_send_all (esh->sock,
524 : &rr,
525 : sizeof (rr)))
526 : {
527 0 : GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
528 : "send");
529 0 : do_disconnect (esh);
530 0 : return;
531 : }
532 : }
533 : }
534 :
535 :
536 : void
537 9 : TALER_CRYPTO_helper_esign_disconnect (
538 : struct TALER_CRYPTO_ExchangeSignHelper *esh)
539 : {
540 9 : if (-1 != esh->sock)
541 9 : do_disconnect (esh);
542 9 : GNUNET_free (esh);
543 9 : }
544 :
545 :
546 : /* end of crypto_helper_esign.c */
|