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