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