crypto_helper_rsa.c (20502B)
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_rsa.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 "crypto_helper_common.h" 25 #include "secmod_rsa.h" 26 #include <poll.h> 27 28 29 struct TALER_CRYPTO_RsaDenominationHelper 30 { 31 /** 32 * Function to call with updates to available key material. 33 */ 34 TALER_CRYPTO_RsaDenominationKeyStatusCallback 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_RsaDenominationHelper *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_RsaDenominationHelper *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_rsa_poll (dh); 109 return GNUNET_OK; 110 } 111 112 113 struct TALER_CRYPTO_RsaDenominationHelper * 114 TALER_CRYPTO_helper_rsa_connect ( 115 const struct GNUNET_CONFIGURATION_Handle *cfg, 116 const char *section, 117 TALER_CRYPTO_RsaDenominationKeyStatusCallback dkc, 118 void *dkc_cls) 119 { 120 struct TALER_CRYPTO_RsaDenominationHelper *dh; 121 char *unixpath; 122 char *secname; 123 124 GNUNET_asprintf (&secname, 125 "%s-secmod-rsa", 126 section); 127 128 if (GNUNET_OK != 129 GNUNET_CONFIGURATION_get_value_filename (cfg, 130 secname, 131 "UNIXPATH", 132 &unixpath)) 133 { 134 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, 135 secname, 136 "UNIXPATH"); 137 GNUNET_free (secname); 138 return NULL; 139 } 140 /* we use >= here because we want the sun_path to always 141 be 0-terminated */ 142 if (strlen (unixpath) >= sizeof (dh->sa.sun_path)) 143 { 144 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, 145 secname, 146 "UNIXPATH", 147 "path too long"); 148 GNUNET_free (unixpath); 149 GNUNET_free (secname); 150 return NULL; 151 } 152 GNUNET_free (secname); 153 dh = GNUNET_new (struct TALER_CRYPTO_RsaDenominationHelper); 154 dh->dkc = dkc; 155 dh->dkc_cls = dkc_cls; 156 dh->sa.sun_family = AF_UNIX; 157 strncpy (dh->sa.sun_path, 158 unixpath, 159 sizeof (dh->sa.sun_path) - 1); 160 GNUNET_free (unixpath); 161 dh->sock = -1; 162 if (GNUNET_OK != 163 try_connect (dh)) 164 { 165 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 166 "Could not connect to %s. Will keep trying\n", 167 "taler-exchange-helper-secmod-rsa"); 168 } 169 return dh; 170 } 171 172 173 /** 174 * Handle a #TALER_HELPER_RSA_MT_AVAIL message from the helper. 175 * 176 * @param dh 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_RsaDenominationHelper *dh, 182 const struct GNUNET_MessageHeader *hdr) 183 { 184 const struct TALER_CRYPTO_RsaKeyAvailableNotification *kan 185 = (const struct TALER_CRYPTO_RsaKeyAvailableNotification *) hdr; 186 const char *buf = (const char *) &kan[1]; 187 const char *section_name; 188 uint16_t ps; 189 uint16_t snl; 190 191 if (sizeof (*kan) > ntohs (hdr->size)) 192 { 193 GNUNET_break_op (0); 194 return GNUNET_SYSERR; 195 } 196 ps = ntohs (kan->pub_size); 197 snl = ntohs (kan->section_name_len); 198 if (ntohs (hdr->size) != sizeof (*kan) + ps + snl) 199 { 200 GNUNET_break_op (0); 201 return GNUNET_SYSERR; 202 } 203 if (0 == snl) 204 { 205 GNUNET_break_op (0); 206 return GNUNET_SYSERR; 207 } 208 section_name = &buf[ps]; 209 if ('\0' != section_name[snl - 1]) 210 { 211 GNUNET_break_op (0); 212 return GNUNET_SYSERR; 213 } 214 215 { 216 struct GNUNET_CRYPTO_BlindSignPublicKey *bs_pub; 217 struct TALER_RsaPubHashP h_rsa; 218 219 bs_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey); 220 bs_pub->cipher = GNUNET_CRYPTO_BSA_RSA; 221 bs_pub->details.rsa_public_key 222 = GNUNET_CRYPTO_rsa_public_key_decode (buf, 223 ntohs (kan->pub_size)); 224 if (NULL == bs_pub->details.rsa_public_key) 225 { 226 GNUNET_break_op (0); 227 GNUNET_free (bs_pub); 228 return GNUNET_SYSERR; 229 } 230 bs_pub->rc = 1; 231 GNUNET_CRYPTO_rsa_public_key_hash (bs_pub->details.rsa_public_key, 232 &bs_pub->pub_key_hash); 233 h_rsa.hash = bs_pub->pub_key_hash; 234 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 235 "Received RSA key %s (%s)\n", 236 GNUNET_h2s (&bs_pub->pub_key_hash), 237 section_name); 238 if (GNUNET_OK != 239 TALER_exchange_secmod_rsa_verify ( 240 &h_rsa, 241 section_name, 242 GNUNET_TIME_timestamp_ntoh (kan->anchor_time), 243 GNUNET_TIME_relative_ntoh (kan->duration_withdraw), 244 &kan->secm_pub, 245 &kan->secm_sig)) 246 { 247 GNUNET_break_op (0); 248 GNUNET_CRYPTO_blind_sign_pub_decref (bs_pub); 249 return GNUNET_SYSERR; 250 } 251 dh->dkc (dh->dkc_cls, 252 section_name, 253 GNUNET_TIME_timestamp_ntoh (kan->anchor_time), 254 GNUNET_TIME_relative_ntoh (kan->duration_withdraw), 255 &h_rsa, 256 bs_pub, 257 &kan->secm_pub, 258 &kan->secm_sig); 259 GNUNET_CRYPTO_blind_sign_pub_decref (bs_pub); 260 } 261 return GNUNET_OK; 262 } 263 264 265 /** 266 * Handle a #TALER_HELPER_RSA_MT_PURGE message from the helper. 267 * 268 * @param dh helper context 269 * @param hdr message that we received 270 * @return #GNUNET_OK on success 271 */ 272 static enum GNUNET_GenericReturnValue 273 handle_mt_purge (struct TALER_CRYPTO_RsaDenominationHelper *dh, 274 const struct GNUNET_MessageHeader *hdr) 275 { 276 const struct TALER_CRYPTO_RsaKeyPurgeNotification *pn 277 = (const struct TALER_CRYPTO_RsaKeyPurgeNotification *) hdr; 278 279 if (sizeof (*pn) != ntohs (hdr->size)) 280 { 281 GNUNET_break_op (0); 282 return GNUNET_SYSERR; 283 } 284 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 285 "Received revocation of denomination key %s\n", 286 GNUNET_h2s (&pn->h_rsa.hash)); 287 dh->dkc (dh->dkc_cls, 288 NULL, 289 GNUNET_TIME_UNIT_ZERO_TS, 290 GNUNET_TIME_UNIT_ZERO, 291 &pn->h_rsa, 292 NULL, 293 NULL, 294 NULL); 295 return GNUNET_OK; 296 } 297 298 299 void 300 TALER_CRYPTO_helper_rsa_poll (struct TALER_CRYPTO_RsaDenominationHelper *dh) 301 { 302 char buf[UINT16_MAX]; 303 size_t off = 0; 304 unsigned int retry_limit = 3; 305 const struct GNUNET_MessageHeader *hdr 306 = (const struct GNUNET_MessageHeader *) buf; 307 308 if (GNUNET_OK != 309 try_connect (dh)) 310 return; /* give up */ 311 while (1) 312 { 313 uint16_t msize; 314 ssize_t ret; 315 316 ret = recv (dh->sock, 317 buf + off, 318 sizeof (buf) - off, 319 (dh->synced && (0 == off)) 320 ? MSG_DONTWAIT 321 : 0); 322 if (ret < 0) 323 { 324 if (EINTR == errno) 325 continue; 326 if (EAGAIN == errno) 327 { 328 GNUNET_assert (dh->synced); 329 GNUNET_assert (0 == off); 330 break; 331 } 332 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 333 "recv"); 334 do_disconnect (dh); 335 if (0 == retry_limit) 336 return; /* give up */ 337 if (GNUNET_OK != 338 try_connect (dh)) 339 return; /* give up */ 340 retry_limit--; 341 continue; 342 } 343 if (0 == ret) 344 { 345 GNUNET_break (0 == off); 346 return; 347 } 348 off += ret; 349 more: 350 if (off < sizeof (struct GNUNET_MessageHeader)) 351 continue; 352 msize = ntohs (hdr->size); 353 if (msize < sizeof (struct GNUNET_MessageHeader)) 354 { 355 GNUNET_break_op (0); 356 do_disconnect (dh); 357 return; 358 } 359 if (off < msize) 360 continue; 361 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 362 "Received message of type %u and length %u\n", 363 (unsigned int) ntohs (hdr->type), 364 (unsigned int) msize); 365 switch (ntohs (hdr->type)) 366 { 367 case TALER_HELPER_RSA_MT_AVAIL: 368 if (GNUNET_OK != 369 handle_mt_avail (dh, 370 hdr)) 371 { 372 GNUNET_break_op (0); 373 do_disconnect (dh); 374 return; 375 } 376 break; 377 case TALER_HELPER_RSA_MT_PURGE: 378 if (GNUNET_OK != 379 handle_mt_purge (dh, 380 hdr)) 381 { 382 GNUNET_break_op (0); 383 do_disconnect (dh); 384 return; 385 } 386 break; 387 case TALER_HELPER_RSA_SYNCED: 388 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 389 "Now synchronized with RSA helper\n"); 390 dh->synced = true; 391 break; 392 default: 393 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 394 "Received unexpected message of type %d (len: %u)\n", 395 (unsigned int) ntohs (hdr->type), 396 (unsigned int) msize); 397 GNUNET_break_op (0); 398 do_disconnect (dh); 399 return; 400 } 401 memmove (buf, 402 &buf[msize], 403 off - msize); 404 off -= msize; 405 goto more; 406 } 407 } 408 409 410 enum TALER_ErrorCode 411 TALER_CRYPTO_helper_rsa_batch_sign ( 412 struct TALER_CRYPTO_RsaDenominationHelper *dh, 413 unsigned int rsrs_length, 414 const struct TALER_CRYPTO_RsaSignRequest rsrs[static rsrs_length], 415 struct TALER_BlindedDenominationSignature bss[static rsrs_length]) 416 { 417 enum TALER_ErrorCode ec = TALER_EC_INVALID; 418 unsigned int rpos; 419 unsigned int rend; 420 unsigned int wpos; 421 422 memset (bss, 423 0, 424 sizeof (*bss) * rsrs_length); 425 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 426 "Starting signature process\n"); 427 if (GNUNET_OK != 428 try_connect (dh)) 429 { 430 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 431 "Failed to connect to helper\n"); 432 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; 433 } 434 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 435 "Requesting %u signatures\n", 436 rsrs_length); 437 rpos = 0; 438 rend = 0; 439 wpos = 0; 440 while (rpos < rsrs_length) 441 { 442 unsigned int mlen = sizeof (struct TALER_CRYPTO_BatchSignRequest); 443 444 while ( (rend < rsrs_length) && 445 (mlen 446 + sizeof (struct TALER_CRYPTO_SignRequest) 447 + rsrs[rend].msg_size < UINT16_MAX) ) 448 { 449 mlen += sizeof (struct TALER_CRYPTO_SignRequest) + rsrs[rend].msg_size; 450 rend++; 451 } 452 { 453 char obuf[mlen] GNUNET_ALIGN; 454 struct TALER_CRYPTO_BatchSignRequest *bsr 455 = (struct TALER_CRYPTO_BatchSignRequest *) obuf; 456 void *wbuf; 457 458 bsr->header.type = htons (TALER_HELPER_RSA_MT_REQ_BATCH_SIGN); 459 bsr->header.size = htons (mlen); 460 bsr->batch_size = htonl (rend - rpos); 461 wbuf = &bsr[1]; 462 for (unsigned int i = rpos; i<rend; i++) 463 { 464 struct TALER_CRYPTO_SignRequest *sr = wbuf; 465 const struct TALER_CRYPTO_RsaSignRequest *rsr = &rsrs[i]; 466 467 sr->header.type = htons (TALER_HELPER_RSA_MT_REQ_SIGN); 468 sr->header.size = htons (sizeof (*sr) + rsr->msg_size); 469 sr->reserved = htonl (0); 470 sr->h_rsa = *rsr->h_rsa; 471 GNUNET_memcpy (&sr[1], 472 rsr->msg, 473 rsr->msg_size); 474 wbuf += sizeof (*sr) + rsr->msg_size; 475 } 476 GNUNET_assert (wbuf == &obuf[mlen]); 477 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 478 "Sending batch request [%u-%u)\n", 479 rpos, 480 rend); 481 if (GNUNET_OK != 482 TALER_crypto_helper_send_all (dh->sock, 483 obuf, 484 sizeof (obuf))) 485 { 486 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 487 "send"); 488 do_disconnect (dh); 489 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; 490 } 491 } 492 rpos = rend; 493 { 494 char buf[UINT16_MAX]; 495 size_t off = 0; 496 const struct GNUNET_MessageHeader *hdr 497 = (const struct GNUNET_MessageHeader *) buf; 498 bool finished = false; 499 500 while (1) 501 { 502 uint16_t msize; 503 ssize_t ret; 504 505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 506 "Awaiting reply at %u (up to %u)\n", 507 wpos, 508 rend); 509 ret = recv (dh->sock, 510 &buf[off], 511 sizeof (buf) - off, 512 (finished && (0 == off)) 513 ? MSG_DONTWAIT 514 : 0); 515 if (ret < 0) 516 { 517 if (EINTR == errno) 518 continue; 519 if (EAGAIN == errno) 520 { 521 GNUNET_assert (finished); 522 GNUNET_assert (0 == off); 523 break; 524 } 525 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 526 "recv"); 527 do_disconnect (dh); 528 ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; 529 break; 530 } 531 if (0 == ret) 532 { 533 GNUNET_break (0 == off); 534 if (! finished) 535 ec = TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG; 536 if (TALER_EC_NONE == ec) 537 break; 538 return ec; 539 } 540 off += ret; 541 more: 542 if (off < sizeof (struct GNUNET_MessageHeader)) 543 continue; 544 msize = ntohs (hdr->size); 545 if (msize < sizeof (struct GNUNET_MessageHeader)) 546 { 547 GNUNET_break_op (0); 548 do_disconnect (dh); 549 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 550 } 551 if (off < msize) 552 continue; 553 switch (ntohs (hdr->type)) 554 { 555 case TALER_HELPER_RSA_MT_RES_SIGNATURE: 556 if (msize < sizeof (struct TALER_CRYPTO_SignResponse)) 557 { 558 GNUNET_break_op (0); 559 do_disconnect (dh); 560 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 561 } 562 if (finished) 563 { 564 GNUNET_break_op (0); 565 do_disconnect (dh); 566 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 567 } 568 { 569 const struct TALER_CRYPTO_SignResponse *sr = 570 (const struct TALER_CRYPTO_SignResponse *) buf; 571 struct GNUNET_CRYPTO_RsaSignature *rsa_signature; 572 struct GNUNET_CRYPTO_BlindedSignature *blind_sig; 573 574 rsa_signature = GNUNET_CRYPTO_rsa_signature_decode ( 575 &sr[1], 576 msize - sizeof (*sr)); 577 if (NULL == rsa_signature) 578 { 579 GNUNET_break_op (0); 580 do_disconnect (dh); 581 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 582 } 583 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 584 "Received %u signature\n", 585 wpos); 586 blind_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature); 587 blind_sig->cipher = GNUNET_CRYPTO_BSA_RSA; 588 blind_sig->rc = 1; 589 blind_sig->details.blinded_rsa_signature = rsa_signature; 590 bss[wpos].blinded_sig = blind_sig; 591 wpos++; 592 if (wpos == rend) 593 { 594 if (TALER_EC_INVALID == ec) 595 ec = TALER_EC_NONE; 596 finished = true; 597 } 598 break; 599 } 600 case TALER_HELPER_RSA_MT_RES_SIGN_FAILURE: 601 if (msize != sizeof (struct TALER_CRYPTO_SignFailure)) 602 { 603 GNUNET_break_op (0); 604 do_disconnect (dh); 605 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 606 } 607 { 608 const struct TALER_CRYPTO_SignFailure *sf = 609 (const struct TALER_CRYPTO_SignFailure *) buf; 610 611 ec = (enum TALER_ErrorCode) (int) ntohl (sf->ec); 612 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 613 "Signing %u failed with status %d!\n", 614 wpos, 615 ec); 616 wpos++; 617 if (wpos == rend) 618 { 619 finished = true; 620 } 621 break; 622 } 623 case TALER_HELPER_RSA_MT_AVAIL: 624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 625 "Received new key!\n"); 626 if (GNUNET_OK != 627 handle_mt_avail (dh, 628 hdr)) 629 { 630 GNUNET_break_op (0); 631 do_disconnect (dh); 632 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 633 } 634 break; /* while(1) loop ensures we recvfrom() again */ 635 case TALER_HELPER_RSA_MT_PURGE: 636 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 637 "Received revocation!\n"); 638 if (GNUNET_OK != 639 handle_mt_purge (dh, 640 hdr)) 641 { 642 GNUNET_break_op (0); 643 do_disconnect (dh); 644 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 645 } 646 break; /* while(1) loop ensures we recvfrom() again */ 647 case TALER_HELPER_RSA_SYNCED: 648 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 649 "Synchronized add odd time with RSA helper!\n"); 650 dh->synced = true; 651 break; 652 default: 653 GNUNET_break_op (0); 654 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 655 "Received unexpected message of type %u\n", 656 ntohs (hdr->type)); 657 do_disconnect (dh); 658 return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG; 659 } 660 memmove (buf, 661 &buf[msize], 662 off - msize); 663 off -= msize; 664 goto more; 665 } /* while(1) */ 666 } /* scope */ 667 } /* while (rpos < rsrs_length) */ 668 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 669 "Existing with %u signatures and status %d\n", 670 wpos, 671 ec); 672 return ec; 673 } 674 675 676 void 677 TALER_CRYPTO_helper_rsa_revoke ( 678 struct TALER_CRYPTO_RsaDenominationHelper *dh, 679 const struct TALER_RsaPubHashP *h_rsa) 680 { 681 struct TALER_CRYPTO_RevokeRequest rr = { 682 .header.size = htons (sizeof (rr)), 683 .header.type = htons (TALER_HELPER_RSA_MT_REQ_REVOKE), 684 .h_rsa = *h_rsa 685 }; 686 687 if (GNUNET_OK != 688 try_connect (dh)) 689 return; /* give up */ 690 if (GNUNET_OK != 691 TALER_crypto_helper_send_all (dh->sock, 692 &rr, 693 sizeof (rr))) 694 { 695 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, 696 "send"); 697 do_disconnect (dh); 698 return; 699 } 700 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 701 "Requested revocation of denomination key %s\n", 702 GNUNET_h2s (&h_rsa->hash)); 703 } 704 705 706 void 707 TALER_CRYPTO_helper_rsa_disconnect ( 708 struct TALER_CRYPTO_RsaDenominationHelper *dh) 709 { 710 if (-1 != dh->sock) 711 do_disconnect (dh); 712 GNUNET_free (dh); 713 } 714 715 716 /* end of crypto_helper_denom.c */