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