crypto_helper_cs.c (38996B)
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 "taler/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 do_disconnect (struct TALER_CRYPTO_CsDenominationHelper *dh) 67 { 68 GNUNET_break (0 == close (dh->sock)); 69 dh->sock = -1; 70 dh->synced = false; 71 } 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 try_connect (struct TALER_CRYPTO_CsDenominationHelper *dh) 83 { 84 if (-1 != dh->sock) 85 return GNUNET_OK; 86 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 87 "Establishing connection!\n"); 88 dh->sock = socket (AF_UNIX, 89 SOCK_STREAM, 90 0); 91 if (-1 == dh->sock) 92 { 93 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 94 "socket"); 95 return GNUNET_SYSERR; 96 } 97 if (0 != 98 connect (dh->sock, 99 (const struct sockaddr *) &dh->sa, 100 sizeof (dh->sa))) 101 { 102 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, 103 "connect", 104 dh->sa.sun_path); 105 do_disconnect (dh); 106 return GNUNET_SYSERR; 107 } 108 TALER_CRYPTO_helper_cs_poll (dh); 109 return GNUNET_OK; 110 } 111 112 113 struct TALER_CRYPTO_CsDenominationHelper * 114 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 GNUNET_asprintf (&secname, 125 "%s-secmod-cs", 126 section); 127 if (GNUNET_OK != 128 GNUNET_CONFIGURATION_get_value_filename (cfg, 129 secname, 130 "UNIXPATH", 131 &unixpath)) 132 { 133 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 134 secname, 135 "UNIXPATH"); 136 GNUNET_free (secname); 137 return NULL; 138 } 139 /* we use >= here because we want the sun_path to always 140 be 0-terminated */ 141 if (strlen (unixpath) >= sizeof (dh->sa.sun_path)) 142 { 143 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 144 secname, 145 "UNIXPATH", 146 "path too long"); 147 GNUNET_free (unixpath); 148 GNUNET_free (secname); 149 return NULL; 150 } 151 GNUNET_free (secname); 152 dh = GNUNET_new (struct TALER_CRYPTO_CsDenominationHelper); 153 dh->dkc = dkc; 154 dh->dkc_cls = dkc_cls; 155 dh->sa.sun_family = AF_UNIX; 156 strncpy (dh->sa.sun_path, 157 unixpath, 158 sizeof (dh->sa.sun_path) - 1); 159 GNUNET_free (unixpath); 160 dh->sock = -1; 161 if (GNUNET_OK != 162 try_connect (dh)) 163 { 164 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 165 "Could not connect to %s. Will keep trying\n", 166 "taler-exchange-helper-secmod-cs"); 167 } 168 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 handle_mt_avail (struct TALER_CRYPTO_CsDenominationHelper *dh, 181 const struct GNUNET_MessageHeader *hdr) 182 { 183 const struct TALER_CRYPTO_CsKeyAvailableNotification *kan 184 = (const struct TALER_CRYPTO_CsKeyAvailableNotification *) hdr; 185 const char *buf = (const char *) &kan[1]; 186 const char *section_name; 187 uint16_t snl; 188 189 if (sizeof (*kan) > ntohs (hdr->size)) 190 { 191 GNUNET_break_op (0); 192 return GNUNET_SYSERR; 193 } 194 snl = ntohs (kan->section_name_len); 195 if (ntohs (hdr->size) != sizeof (*kan) + snl) 196 { 197 GNUNET_break_op (0); 198 return GNUNET_SYSERR; 199 } 200 if (0 == snl) 201 { 202 GNUNET_break_op (0); 203 return GNUNET_SYSERR; 204 } 205 section_name = buf; 206 if ('\0' != section_name[snl - 1]) 207 { 208 GNUNET_break_op (0); 209 return GNUNET_SYSERR; 210 } 211 212 { 213 struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub; 214 struct TALER_CsPubHashP h_cs; 215 216 bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey); 217 bsign_pub->cipher = GNUNET_CRYPTO_BSA_CS; 218 bsign_pub->rc = 1; 219 bsign_pub->details.cs_public_key = kan->denom_pub; 220 221 GNUNET_CRYPTO_hash (&bsign_pub->details.cs_public_key, 222 sizeof (bsign_pub->details.cs_public_key), 223 &bsign_pub->pub_key_hash); 224 h_cs.hash = bsign_pub->pub_key_hash; 225 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 226 "Received CS key %s (%s)\n", 227 GNUNET_h2s (&h_cs.hash), 228 section_name); 229 if (GNUNET_OK != 230 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 GNUNET_break_op (0); 239 GNUNET_CRYPTO_blind_sign_pub_decref (bsign_pub); 240 return GNUNET_SYSERR; 241 } 242 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 GNUNET_CRYPTO_blind_sign_pub_decref (bsign_pub); 251 } 252 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 handle_mt_purge (struct TALER_CRYPTO_CsDenominationHelper *dh, 265 const struct GNUNET_MessageHeader *hdr) 266 { 267 const struct TALER_CRYPTO_CsKeyPurgeNotification *pn 268 = (const struct TALER_CRYPTO_CsKeyPurgeNotification *) hdr; 269 270 if (sizeof (*pn) != ntohs (hdr->size)) 271 { 272 GNUNET_break_op (0); 273 return GNUNET_SYSERR; 274 } 275 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 276 "Received revocation of denomination key %s\n", 277 GNUNET_h2s (&pn->h_cs.hash)); 278 dh->dkc (dh->dkc_cls, 279 NULL, 280 GNUNET_TIME_UNIT_ZERO_TS, 281 GNUNET_TIME_UNIT_ZERO, 282 &pn->h_cs, 283 NULL, 284 NULL, 285 NULL); 286 return GNUNET_OK; 287 } 288 289 290 void 291 TALER_CRYPTO_helper_cs_poll (struct TALER_CRYPTO_CsDenominationHelper *dh) 292 { 293 char buf[UINT16_MAX]; 294 size_t off = 0; 295 unsigned int retry_limit = 3; 296 const struct GNUNET_MessageHeader *hdr 297 = (const struct GNUNET_MessageHeader *) buf; 298 299 if (GNUNET_OK != 300 try_connect (dh)) 301 return; /* give up */ 302 while (1) 303 { 304 uint16_t msize; 305 ssize_t ret; 306 307 ret = recv (dh->sock, 308 buf + off, 309 sizeof (buf) - off, 310 (dh->synced && (0 == off)) 311 ? MSG_DONTWAIT 312 : 0); 313 if (ret < 0) 314 { 315 if (EINTR == errno) 316 continue; 317 if (EAGAIN == errno) 318 { 319 GNUNET_assert (dh->synced); 320 GNUNET_assert (0 == off); 321 break; 322 } 323 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 324 "recv"); 325 do_disconnect (dh); 326 if (0 == retry_limit) 327 return; /* give up */ 328 if (GNUNET_OK != 329 try_connect (dh)) 330 return; /* give up */ 331 retry_limit--; 332 continue; 333 } 334 if (0 == ret) 335 { 336 GNUNET_break (0 == off); 337 return; 338 } 339 off += ret; 340 more: 341 if (off < sizeof (struct GNUNET_MessageHeader)) 342 continue; 343 msize = ntohs (hdr->size); 344 if (off < msize) 345 continue; 346 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 switch (ntohs (hdr->type)) 351 { 352 case TALER_HELPER_CS_MT_AVAIL: 353 if (GNUNET_OK != 354 handle_mt_avail (dh, 355 hdr)) 356 { 357 GNUNET_break_op (0); 358 do_disconnect (dh); 359 return; 360 } 361 break; 362 case TALER_HELPER_CS_MT_PURGE: 363 if (GNUNET_OK != 364 handle_mt_purge (dh, 365 hdr)) 366 { 367 GNUNET_break_op (0); 368 do_disconnect (dh); 369 return; 370 } 371 break; 372 case TALER_HELPER_CS_SYNCED: 373 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 374 "Now synchronized with CS helper\n"); 375 dh->synced = true; 376 break; 377 default: 378 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 GNUNET_break_op (0); 383 do_disconnect (dh); 384 return; 385 } 386 memmove (buf, 387 &buf[msize], 388 off - msize); 389 off -= msize; 390 goto more; 391 } 392 } 393 394 395 enum TALER_ErrorCode 396 TALER_CRYPTO_helper_cs_sign ( 397 struct TALER_CRYPTO_CsDenominationHelper *dh, 398 const struct TALER_CRYPTO_CsSignRequest *req, 399 bool for_melt, 400 struct TALER_BlindedDenominationSignature *bs) 401 { 402 enum TALER_ErrorCode ec = TALER_EC_INVALID; 403 const struct TALER_CsPubHashP *h_cs = req->h_cs; 404 405 memset (bs, 406 0, 407 sizeof (*bs)); 408 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 409 "Starting signature process\n"); 410 if (GNUNET_OK != 411 try_connect (dh)) 412 { 413 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 414 "Failed to connect to helper\n"); 415 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; 416 } 417 418 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 419 "Requesting signature\n"); 420 { 421 char buf[sizeof (struct TALER_CRYPTO_CsSignRequestMessage)]; 422 struct TALER_CRYPTO_CsSignRequestMessage *sr 423 = (struct TALER_CRYPTO_CsSignRequestMessage *) buf; 424 425 sr->header.size = htons (sizeof (buf)); 426 sr->header.type = htons (TALER_HELPER_CS_MT_REQ_SIGN); 427 sr->for_melt = htonl (for_melt ? 1 : 0); 428 sr->h_cs = *h_cs; 429 sr->message = *req->blinded_planchet; 430 if (GNUNET_OK != 431 TALER_crypto_helper_send_all (dh->sock, 432 buf, 433 sizeof (buf))) 434 { 435 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 436 "send"); 437 do_disconnect (dh); 438 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; 439 } 440 } 441 442 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 443 "Awaiting reply\n"); 444 { 445 char buf[UINT16_MAX]; 446 size_t off = 0; 447 const struct GNUNET_MessageHeader *hdr 448 = (const struct GNUNET_MessageHeader *) buf; 449 bool finished = false; 450 451 while (1) 452 { 453 uint16_t msize; 454 ssize_t ret; 455 456 ret = recv (dh->sock, 457 &buf[off], 458 sizeof (buf) - off, 459 (finished && (0 == off)) 460 ? MSG_DONTWAIT 461 : 0); 462 if (ret < 0) 463 { 464 if (EINTR == errno) 465 continue; 466 if (EAGAIN == errno) 467 { 468 GNUNET_assert (finished); 469 GNUNET_assert (0 == off); 470 return ec; 471 } 472 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 473 "recv"); 474 do_disconnect (dh); 475 ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; 476 break; 477 } 478 if (0 == ret) 479 { 480 GNUNET_break (0 == off); 481 if (! finished) 482 ec = TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; 483 return ec; 484 } 485 off += ret; 486 more: 487 if (off < sizeof (struct GNUNET_MessageHeader)) 488 continue; 489 msize = ntohs (hdr->size); 490 if (off < msize) 491 continue; 492 switch (ntohs (hdr->type)) 493 { 494 case TALER_HELPER_CS_MT_RES_SIGNATURE: 495 if (msize != sizeof (struct TALER_CRYPTO_SignResponse)) 496 { 497 GNUNET_break_op (0); 498 do_disconnect (dh); 499 ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 500 goto end; 501 } 502 if (finished) 503 { 504 GNUNET_break_op (0); 505 do_disconnect (dh); 506 ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 507 goto end; 508 } 509 { 510 const struct TALER_CRYPTO_SignResponse *sr = 511 (const struct TALER_CRYPTO_SignResponse *) buf; 512 struct GNUNET_CRYPTO_BlindedSignature *blinded_sig; 513 514 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 515 "Received signature\n"); 516 ec = TALER_EC_NONE; 517 finished = true; 518 blinded_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature); 519 blinded_sig->cipher = GNUNET_CRYPTO_BSA_CS; 520 blinded_sig->rc = 1; 521 blinded_sig->details.blinded_cs_answer.b = ntohl (sr->b); 522 blinded_sig->details.blinded_cs_answer.s_scalar = sr->cs_answer; 523 bs->blinded_sig = blinded_sig; 524 break; 525 } 526 case TALER_HELPER_CS_MT_RES_SIGN_FAILURE: 527 if (msize != sizeof (struct TALER_CRYPTO_SignFailure)) 528 { 529 GNUNET_break_op (0); 530 do_disconnect (dh); 531 ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 532 goto end; 533 } 534 { 535 const struct TALER_CRYPTO_SignFailure *sf = 536 (const struct TALER_CRYPTO_SignFailure *) buf; 537 538 ec = (enum TALER_ErrorCode) (int) ntohl (sf->ec); 539 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 540 "Signing failed with status %d!\n", 541 ec); 542 finished = true; 543 break; 544 } 545 case TALER_HELPER_CS_MT_AVAIL: 546 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 547 "Received new key!\n"); 548 if (GNUNET_OK != 549 handle_mt_avail (dh, 550 hdr)) 551 { 552 GNUNET_break_op (0); 553 do_disconnect (dh); 554 ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 555 goto end; 556 } 557 break; /* while(1) loop ensures we recvfrom() again */ 558 case TALER_HELPER_CS_MT_PURGE: 559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 560 "Received revocation!\n"); 561 if (GNUNET_OK != 562 handle_mt_purge (dh, 563 hdr)) 564 { 565 GNUNET_break_op (0); 566 do_disconnect (dh); 567 ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 568 goto end; 569 } 570 break; /* while(1) loop ensures we recvfrom() again */ 571 case TALER_HELPER_CS_SYNCED: 572 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 573 "Synchronized add odd time with CS helper!\n"); 574 dh->synced = true; 575 break; 576 default: 577 GNUNET_break_op (0); 578 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 579 "Received unexpected message of type %u\n", 580 ntohs (hdr->type)); 581 do_disconnect (dh); 582 ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 583 goto end; 584 } 585 memmove (buf, 586 &buf[msize], 587 off - msize); 588 off -= msize; 589 goto more; 590 } /* while(1) */ 591 end: 592 if (finished) 593 TALER_blinded_denom_sig_free (bs); 594 return ec; 595 } 596 } 597 598 599 void 600 TALER_CRYPTO_helper_cs_revoke ( 601 struct TALER_CRYPTO_CsDenominationHelper *dh, 602 const struct TALER_CsPubHashP *h_cs) 603 { 604 struct TALER_CRYPTO_CsRevokeRequest rr = { 605 .header.size = htons (sizeof (rr)), 606 .header.type = htons (TALER_HELPER_CS_MT_REQ_REVOKE), 607 .h_cs = *h_cs 608 }; 609 610 if (GNUNET_OK != 611 try_connect (dh)) 612 return; /* give up */ 613 if (GNUNET_OK != 614 TALER_crypto_helper_send_all (dh->sock, 615 &rr, 616 sizeof (rr))) 617 { 618 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 619 "send"); 620 do_disconnect (dh); 621 return; 622 } 623 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 624 "Requested revocation of denomination key %s\n", 625 GNUNET_h2s (&h_cs->hash)); 626 } 627 628 629 enum TALER_ErrorCode 630 TALER_CRYPTO_helper_cs_r_derive (struct TALER_CRYPTO_CsDenominationHelper *dh, 631 const struct TALER_CRYPTO_CsDeriveRequest *cdr, 632 bool for_melt, 633 struct GNUNET_CRYPTO_CSPublicRPairP *crp) 634 { 635 enum TALER_ErrorCode ec = TALER_EC_INVALID; 636 const struct TALER_CsPubHashP *h_cs = cdr->h_cs; 637 const struct GNUNET_CRYPTO_CsSessionNonce *nonce = cdr->nonce; 638 639 memset (crp, 640 0, 641 sizeof (*crp)); 642 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 643 "Starting R derivation process\n"); 644 if (GNUNET_OK != 645 try_connect (dh)) 646 { 647 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 648 "Failed to connect to helper\n"); 649 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; 650 } 651 652 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 653 "Requesting R\n"); 654 { 655 struct TALER_CRYPTO_CsRDeriveRequest rdr = { 656 .header.size = htons (sizeof (rdr)), 657 .header.type = htons (TALER_HELPER_CS_MT_REQ_RDERIVE), 658 .for_melt = htonl (for_melt ? 1 : 0), 659 .h_cs = *h_cs, 660 .nonce = *nonce 661 }; 662 663 if (GNUNET_OK != 664 TALER_crypto_helper_send_all (dh->sock, 665 &rdr, 666 sizeof (rdr))) 667 { 668 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 669 "send"); 670 do_disconnect (dh); 671 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; 672 } 673 } 674 675 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 676 "Awaiting reply\n"); 677 { 678 char buf[UINT16_MAX]; 679 size_t off = 0; 680 const struct GNUNET_MessageHeader *hdr 681 = (const struct GNUNET_MessageHeader *) buf; 682 bool finished = false; 683 684 while (1) 685 { 686 uint16_t msize; 687 ssize_t ret; 688 689 ret = recv (dh->sock, 690 &buf[off], 691 sizeof (buf) - off, 692 (finished && (0 == off)) 693 ? MSG_DONTWAIT 694 : 0); 695 if (ret < 0) 696 { 697 if (EINTR == errno) 698 continue; 699 if (EAGAIN == errno) 700 { 701 GNUNET_assert (finished); 702 GNUNET_assert (0 == off); 703 return ec; 704 } 705 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 706 "recv"); 707 do_disconnect (dh); 708 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; 709 } 710 if (0 == ret) 711 { 712 GNUNET_break (0 == off); 713 if (! finished) 714 return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; 715 return ec; 716 } 717 off += ret; 718 more: 719 if (off < sizeof (struct GNUNET_MessageHeader)) 720 continue; 721 msize = ntohs (hdr->size); 722 if (off < msize) 723 continue; 724 switch (ntohs (hdr->type)) 725 { 726 case TALER_HELPER_CS_MT_RES_RDERIVE: 727 if (msize != sizeof (struct TALER_CRYPTO_RDeriveResponse)) 728 { 729 GNUNET_break_op (0); 730 do_disconnect (dh); 731 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 732 } 733 if (finished) 734 { 735 GNUNET_break_op (0); 736 do_disconnect (dh); 737 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 738 } 739 { 740 const struct TALER_CRYPTO_RDeriveResponse *rdr = 741 (const struct TALER_CRYPTO_RDeriveResponse *) buf; 742 743 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 744 "Received R\n"); 745 finished = true; 746 ec = TALER_EC_NONE; 747 *crp = rdr->r_pub; 748 break; 749 } 750 case TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE: 751 if (msize != sizeof (struct TALER_CRYPTO_RDeriveFailure)) 752 { 753 GNUNET_break_op (0); 754 do_disconnect (dh); 755 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 756 } 757 { 758 const struct TALER_CRYPTO_RDeriveFailure *rdf = 759 (const struct TALER_CRYPTO_RDeriveFailure *) buf; 760 761 ec = (enum TALER_ErrorCode) (int) ntohl (rdf->ec); 762 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 763 "R derivation failed!\n"); 764 finished = true; 765 break; 766 } 767 case TALER_HELPER_CS_MT_AVAIL: 768 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 769 "Received new key!\n"); 770 if (GNUNET_OK != 771 handle_mt_avail (dh, 772 hdr)) 773 { 774 GNUNET_break_op (0); 775 do_disconnect (dh); 776 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 777 } 778 break; /* while(1) loop ensures we recvfrom() again */ 779 case TALER_HELPER_CS_MT_PURGE: 780 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 781 "Received revocation!\n"); 782 if (GNUNET_OK != 783 handle_mt_purge (dh, 784 hdr)) 785 { 786 GNUNET_break_op (0); 787 do_disconnect (dh); 788 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 789 } 790 break; /* while(1) loop ensures we recvfrom() again */ 791 case TALER_HELPER_CS_SYNCED: 792 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 793 "Synchronized add odd time with CS helper!\n"); 794 dh->synced = true; 795 break; 796 default: 797 GNUNET_break_op (0); 798 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 799 "Received unexpected message of type %u\n", 800 ntohs (hdr->type)); 801 do_disconnect (dh); 802 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 803 } 804 memmove (buf, 805 &buf[msize], 806 off - msize); 807 off -= msize; 808 goto more; 809 } /* while(1) */ 810 } 811 } 812 813 814 enum TALER_ErrorCode 815 TALER_CRYPTO_helper_cs_batch_sign ( 816 struct TALER_CRYPTO_CsDenominationHelper *dh, 817 unsigned int reqs_length, 818 const struct TALER_CRYPTO_CsSignRequest reqs[static reqs_length], 819 bool for_melt, 820 struct TALER_BlindedDenominationSignature bss[static reqs_length]) 821 { 822 enum TALER_ErrorCode ec = TALER_EC_INVALID; 823 unsigned int rpos; 824 unsigned int rend; 825 unsigned int wpos; 826 827 memset (bss, 828 0, 829 sizeof (*bss) * reqs_length); 830 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 831 "Starting signature process\n"); 832 if (GNUNET_OK != 833 try_connect (dh)) 834 { 835 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 836 "Failed to connect to helper\n"); 837 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; 838 } 839 840 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 841 "Requesting %u signatures\n", 842 reqs_length); 843 rpos = 0; 844 rend = 0; 845 wpos = 0; 846 while (rpos < reqs_length) 847 { 848 unsigned int mlen = sizeof (struct TALER_CRYPTO_BatchSignRequest); 849 850 while ( (rend < reqs_length) && 851 (mlen + sizeof (struct TALER_CRYPTO_CsSignRequestMessage) 852 < UINT16_MAX) ) 853 { 854 mlen += sizeof (struct TALER_CRYPTO_CsSignRequestMessage); 855 rend++; 856 } 857 { 858 char obuf[mlen] GNUNET_ALIGN; 859 struct TALER_CRYPTO_BatchSignRequest *bsr 860 = (struct TALER_CRYPTO_BatchSignRequest *) obuf; 861 void *wbuf; 862 863 bsr->header.type = htons (TALER_HELPER_CS_MT_REQ_BATCH_SIGN); 864 bsr->header.size = htons (mlen); 865 bsr->batch_size = htonl (rend - rpos); 866 wbuf = &bsr[1]; 867 for (unsigned int i = rpos; i<rend; i++) 868 { 869 struct TALER_CRYPTO_CsSignRequestMessage *csm = wbuf; 870 const struct TALER_CRYPTO_CsSignRequest *csr = &reqs[i]; 871 872 csm->header.size = htons (sizeof (*csm)); 873 csm->header.type = htons (TALER_HELPER_CS_MT_REQ_SIGN); 874 csm->for_melt = htonl (for_melt ? 1 : 0); 875 csm->h_cs = *csr->h_cs; 876 csm->message = *csr->blinded_planchet; 877 wbuf += sizeof (*csm); 878 } 879 GNUNET_assert (wbuf == &obuf[mlen]); 880 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 881 "Sending batch request [%u-%u)\n", 882 rpos, 883 rend); 884 if (GNUNET_OK != 885 TALER_crypto_helper_send_all (dh->sock, 886 obuf, 887 sizeof (obuf))) 888 { 889 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 890 "send"); 891 do_disconnect (dh); 892 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; 893 } 894 } /* end of obuf scope */ 895 rpos = rend; 896 { 897 char buf[UINT16_MAX]; 898 size_t off = 0; 899 const struct GNUNET_MessageHeader *hdr 900 = (const struct GNUNET_MessageHeader *) buf; 901 bool finished = false; 902 903 while (1) 904 { 905 uint16_t msize; 906 ssize_t ret; 907 908 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 909 "Awaiting reply at %u (up to %u)\n", 910 wpos, 911 rend); 912 ret = recv (dh->sock, 913 &buf[off], 914 sizeof (buf) - off, 915 (finished && (0 == off)) 916 ? MSG_DONTWAIT 917 : 0); 918 if (ret < 0) 919 { 920 if (EINTR == errno) 921 continue; 922 if (EAGAIN == errno) 923 { 924 GNUNET_assert (finished); 925 GNUNET_assert (0 == off); 926 break; 927 } 928 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 929 "recv"); 930 do_disconnect (dh); 931 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; 932 } 933 if (0 == ret) 934 { 935 GNUNET_break (0 == off); 936 if (! finished) 937 return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; 938 if (TALER_EC_NONE == ec) 939 break; 940 return ec; 941 } 942 off += ret; 943 more: 944 if (off < sizeof (struct GNUNET_MessageHeader)) 945 continue; 946 msize = ntohs (hdr->size); 947 if (off < msize) 948 continue; 949 switch (ntohs (hdr->type)) 950 { 951 case TALER_HELPER_CS_MT_RES_SIGNATURE: 952 if (msize != sizeof (struct TALER_CRYPTO_SignResponse)) 953 { 954 GNUNET_break_op (0); 955 do_disconnect (dh); 956 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 957 } 958 if (finished) 959 { 960 GNUNET_break_op (0); 961 do_disconnect (dh); 962 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 963 } 964 { 965 const struct TALER_CRYPTO_SignResponse *sr = 966 (const struct TALER_CRYPTO_SignResponse *) buf; 967 struct GNUNET_CRYPTO_BlindedSignature *blinded_sig; 968 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 969 "Received %u signature\n", 970 wpos); 971 blinded_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature); 972 blinded_sig->cipher = GNUNET_CRYPTO_BSA_CS; 973 blinded_sig->rc = 1; 974 blinded_sig->details.blinded_cs_answer.b = ntohl (sr->b); 975 blinded_sig->details.blinded_cs_answer.s_scalar = sr->cs_answer; 976 977 bss[wpos].blinded_sig = blinded_sig; 978 wpos++; 979 if (wpos == rend) 980 { 981 if (TALER_EC_INVALID == ec) 982 ec = TALER_EC_NONE; 983 finished = true; 984 } 985 break; 986 } 987 988 case TALER_HELPER_CS_MT_RES_SIGN_FAILURE: 989 if (msize != sizeof (struct TALER_CRYPTO_SignFailure)) 990 { 991 GNUNET_break_op (0); 992 do_disconnect (dh); 993 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 994 } 995 { 996 const struct TALER_CRYPTO_SignFailure *sf = 997 (const struct TALER_CRYPTO_SignFailure *) buf; 998 999 ec = (enum TALER_ErrorCode) (int) ntohl (sf->ec); 1000 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1001 "Signing %u failed with status %d!\n", 1002 wpos, 1003 ec); 1004 wpos++; 1005 if (wpos == rend) 1006 { 1007 finished = true; 1008 } 1009 break; 1010 } 1011 case TALER_HELPER_CS_MT_AVAIL: 1012 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1013 "Received new key!\n"); 1014 if (GNUNET_OK != 1015 handle_mt_avail (dh, 1016 hdr)) 1017 { 1018 GNUNET_break_op (0); 1019 do_disconnect (dh); 1020 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 1021 } 1022 break; /* while(1) loop ensures we recvfrom() again */ 1023 case TALER_HELPER_CS_MT_PURGE: 1024 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1025 "Received revocation!\n"); 1026 if (GNUNET_OK != 1027 handle_mt_purge (dh, 1028 hdr)) 1029 { 1030 GNUNET_break_op (0); 1031 do_disconnect (dh); 1032 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 1033 } 1034 break; /* while(1) loop ensures we recvfrom() again */ 1035 case TALER_HELPER_CS_SYNCED: 1036 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1037 "Synchronized add odd time with CS helper!\n"); 1038 dh->synced = true; 1039 break; 1040 default: 1041 GNUNET_break_op (0); 1042 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1043 "Received unexpected message of type %u\n", 1044 ntohs (hdr->type)); 1045 do_disconnect (dh); 1046 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 1047 } 1048 memmove (buf, 1049 &buf[msize], 1050 off - msize); 1051 off -= msize; 1052 goto more; 1053 } /* while(1) */ 1054 } /* scope */ 1055 } /* while (rpos < cdrs_length) */ 1056 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1057 "Existing with %u signatures and status %d\n", 1058 wpos, 1059 ec); 1060 return ec; 1061 } 1062 1063 1064 enum TALER_ErrorCode 1065 TALER_CRYPTO_helper_cs_r_batch_derive ( 1066 struct TALER_CRYPTO_CsDenominationHelper *dh, 1067 unsigned int cdrs_length, 1068 const struct TALER_CRYPTO_CsDeriveRequest cdrs[static cdrs_length], 1069 bool for_melt, 1070 struct GNUNET_CRYPTO_CSPublicRPairP crps[static cdrs_length]) 1071 { 1072 enum TALER_ErrorCode ec = TALER_EC_INVALID; 1073 unsigned int rpos; 1074 unsigned int rend; 1075 unsigned int wpos; 1076 1077 memset (crps, 1078 0, 1079 sizeof (*crps) * cdrs_length); 1080 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1081 "Starting R derivation process\n"); 1082 if (GNUNET_OK != 1083 try_connect (dh)) 1084 { 1085 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1086 "Failed to connect to helper\n"); 1087 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; 1088 } 1089 1090 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1091 "Requesting %u R pairs\n", 1092 cdrs_length); 1093 rpos = 0; 1094 rend = 0; 1095 wpos = 0; 1096 while (rpos < cdrs_length) 1097 { 1098 unsigned int mlen = sizeof (struct TALER_CRYPTO_BatchDeriveRequest); 1099 1100 while ( (rend < cdrs_length) && 1101 (mlen + sizeof (struct TALER_CRYPTO_CsRDeriveRequest) 1102 < UINT16_MAX) ) 1103 { 1104 mlen += sizeof (struct TALER_CRYPTO_CsRDeriveRequest); 1105 rend++; 1106 } 1107 { 1108 char obuf[mlen] GNUNET_ALIGN; 1109 struct TALER_CRYPTO_BatchDeriveRequest *bdr 1110 = (struct TALER_CRYPTO_BatchDeriveRequest *) obuf; 1111 void *wbuf; 1112 1113 bdr->header.type = htons (TALER_HELPER_CS_MT_REQ_BATCH_RDERIVE); 1114 bdr->header.size = htons (mlen); 1115 bdr->batch_size = htonl (rend - rpos); 1116 wbuf = &bdr[1]; 1117 for (unsigned int i = rpos; i<rend; i++) 1118 { 1119 struct TALER_CRYPTO_CsRDeriveRequest *rdr = wbuf; 1120 const struct TALER_CRYPTO_CsDeriveRequest *cdr = &cdrs[i]; 1121 1122 rdr->header.size = htons (sizeof (*rdr)); 1123 rdr->header.type = htons (TALER_HELPER_CS_MT_REQ_RDERIVE); 1124 rdr->for_melt = htonl (for_melt ? 1 : 0); 1125 rdr->h_cs = *cdr->h_cs; 1126 rdr->nonce = *cdr->nonce; 1127 wbuf += sizeof (*rdr); 1128 } 1129 GNUNET_assert (wbuf == &obuf[mlen]); 1130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1131 "Sending batch request [%u-%u)\n", 1132 rpos, 1133 rend); 1134 if (GNUNET_OK != 1135 TALER_crypto_helper_send_all (dh->sock, 1136 obuf, 1137 sizeof (obuf))) 1138 { 1139 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 1140 "send"); 1141 do_disconnect (dh); 1142 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; 1143 } 1144 } /* end of obuf scope */ 1145 rpos = rend; 1146 { 1147 char buf[UINT16_MAX]; 1148 size_t off = 0; 1149 const struct GNUNET_MessageHeader *hdr 1150 = (const struct GNUNET_MessageHeader *) buf; 1151 bool finished = false; 1152 1153 while (1) 1154 { 1155 uint16_t msize; 1156 ssize_t ret; 1157 1158 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1159 "Awaiting reply at %u (up to %u)\n", 1160 wpos, 1161 rend); 1162 ret = recv (dh->sock, 1163 &buf[off], 1164 sizeof (buf) - off, 1165 (finished && (0 == off)) 1166 ? MSG_DONTWAIT 1167 : 0); 1168 if (ret < 0) 1169 { 1170 if (EINTR == errno) 1171 continue; 1172 if (EAGAIN == errno) 1173 { 1174 GNUNET_assert (finished); 1175 GNUNET_assert (0 == off); 1176 break; 1177 } 1178 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 1179 "recv"); 1180 do_disconnect (dh); 1181 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; 1182 } 1183 if (0 == ret) 1184 { 1185 GNUNET_break (0 == off); 1186 if (! finished) 1187 return TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; 1188 if (TALER_EC_NONE == ec) 1189 break; 1190 return ec; 1191 } 1192 off += ret; 1193 more: 1194 if (off < sizeof (struct GNUNET_MessageHeader)) 1195 continue; 1196 msize = ntohs (hdr->size); 1197 if (off < msize) 1198 continue; 1199 switch (ntohs (hdr->type)) 1200 { 1201 case TALER_HELPER_CS_MT_RES_RDERIVE: 1202 if (msize != sizeof (struct TALER_CRYPTO_RDeriveResponse)) 1203 { 1204 GNUNET_break_op (0); 1205 do_disconnect (dh); 1206 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 1207 } 1208 if (finished) 1209 { 1210 GNUNET_break_op (0); 1211 do_disconnect (dh); 1212 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 1213 } 1214 { 1215 const struct TALER_CRYPTO_RDeriveResponse *rdr = 1216 (const struct TALER_CRYPTO_RDeriveResponse *) buf; 1217 1218 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1219 "Received %u R pair\n", 1220 wpos); 1221 crps[wpos] = rdr->r_pub; 1222 wpos++; 1223 if (wpos == rend) 1224 { 1225 if (TALER_EC_INVALID == ec) 1226 ec = TALER_EC_NONE; 1227 finished = true; 1228 } 1229 break; 1230 } 1231 case TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE: 1232 if (msize != sizeof (struct TALER_CRYPTO_RDeriveFailure)) 1233 { 1234 GNUNET_break_op (0); 1235 do_disconnect (dh); 1236 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 1237 } 1238 { 1239 const struct TALER_CRYPTO_RDeriveFailure *rdf = 1240 (const struct TALER_CRYPTO_RDeriveFailure *) buf; 1241 1242 ec = (enum TALER_ErrorCode) (int) ntohl (rdf->ec); 1243 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1244 "R derivation %u failed with status %d!\n", 1245 wpos, 1246 ec); 1247 wpos++; 1248 if (wpos == rend) 1249 { 1250 finished = true; 1251 } 1252 break; 1253 } 1254 case TALER_HELPER_CS_MT_AVAIL: 1255 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1256 "Received new key!\n"); 1257 if (GNUNET_OK != 1258 handle_mt_avail (dh, 1259 hdr)) 1260 { 1261 GNUNET_break_op (0); 1262 do_disconnect (dh); 1263 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 1264 } 1265 break; /* while(1) loop ensures we recvfrom() again */ 1266 case TALER_HELPER_CS_MT_PURGE: 1267 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1268 "Received revocation!\n"); 1269 if (GNUNET_OK != 1270 handle_mt_purge (dh, 1271 hdr)) 1272 { 1273 GNUNET_break_op (0); 1274 do_disconnect (dh); 1275 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 1276 } 1277 break; /* while(1) loop ensures we recvfrom() again */ 1278 case TALER_HELPER_CS_SYNCED: 1279 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 1280 "Synchronized add odd time with CS helper!\n"); 1281 dh->synced = true; 1282 break; 1283 default: 1284 GNUNET_break_op (0); 1285 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1286 "Received unexpected message of type %u\n", 1287 ntohs (hdr->type)); 1288 do_disconnect (dh); 1289 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 1290 } 1291 memmove (buf, 1292 &buf[msize], 1293 off - msize); 1294 off -= msize; 1295 goto more; 1296 } /* while(1) */ 1297 } /* scope */ 1298 } /* while (rpos < cdrs_length) */ 1299 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 1300 "Existing with %u signatures and status %d\n", 1301 wpos, 1302 ec); 1303 return ec; 1304 } 1305 1306 1307 void 1308 TALER_CRYPTO_helper_cs_disconnect ( 1309 struct TALER_CRYPTO_CsDenominationHelper *dh) 1310 { 1311 if (-1 != dh->sock) 1312 do_disconnect (dh); 1313 GNUNET_free (dh); 1314 } 1315 1316 1317 /* end of crypto_helper_cs.c */