test_helper_cs.c (36611B)
1 /* 2 This file is part of TALER 3 (C) 2020, 2021, 2023 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/test_helper_cs.c 18 * @brief Tests for CS crypto helper 19 * @author Christian Grothoff 20 */ 21 #include "taler/platform.h" 22 #include "taler/taler_util.h" 23 24 /** 25 * Configuration has 1 minute duration and 5 minutes lookahead, but 26 * we do not get 'revocations' for expired keys. So this must be 27 * large enough to deal with key rotation during the runtime of 28 * the benchmark. 29 */ 30 #define MAX_KEYS 1024 31 32 /** 33 * How many random key revocations should we test? 34 */ 35 #define NUM_REVOKES 3 36 37 /** 38 * How many iterations of the successful signing test should we run? 39 */ 40 #define NUM_SIGN_TESTS 5 41 42 /** 43 * How many iterations of the successful signing test should we run 44 * during the benchmark phase? 45 */ 46 #define NUM_SIGN_PERFS 100 47 48 /** 49 * How many parallel clients should we use for the parallel 50 * benchmark? (> 500 may cause problems with the max open FD number limit). 51 */ 52 #define NUM_CORES 8 53 54 /** 55 * Number of keys currently in #keys. 56 */ 57 static unsigned int num_keys; 58 59 /** 60 * Keys currently managed by the helper. 61 */ 62 struct KeyData 63 { 64 /** 65 * Validity start point. 66 */ 67 struct GNUNET_TIME_Timestamp start_time; 68 69 /** 70 * Key expires for signing at @e start_time plus this value. 71 */ 72 struct GNUNET_TIME_Relative validity_duration; 73 74 /** 75 * Hash of the public key. 76 */ 77 struct TALER_CsPubHashP h_cs; 78 79 /** 80 * Full public key. 81 */ 82 struct TALER_DenominationPublicKey denom_pub; 83 84 /** 85 * Is this key currently valid? 86 */ 87 bool valid; 88 89 /** 90 * Did the test driver revoke this key? 91 */ 92 bool revoked; 93 }; 94 95 /** 96 * Array of all the keys we got from the helper. 97 */ 98 static struct KeyData keys[MAX_KEYS]; 99 100 101 /** 102 * Release memory occupied by #keys. 103 */ 104 static void 105 free_keys (void) 106 { 107 for (unsigned int i = 0; i<MAX_KEYS; i++) 108 if (keys[i].valid) 109 { 110 TALER_denom_pub_free (&keys[i].denom_pub); 111 keys[i].valid = false; 112 GNUNET_assert (num_keys > 0); 113 num_keys--; 114 } 115 } 116 117 118 /** 119 * Function called with information about available keys for signing. Usually 120 * only called once per key upon connect. Also called again in case a key is 121 * being revoked, in that case with an @a end_time of zero. Stores the keys 122 * status in #keys. 123 * 124 * @param cls closure, NULL 125 * @param section_name name of the denomination type in the configuration; 126 * NULL if the key has been revoked or purged 127 * @param start_time when does the key become available for signing; 128 * zero if the key has been revoked or purged 129 * @param validity_duration how long does the key remain available for signing; 130 * zero if the key has been revoked or purged 131 * @param h_cs hash of the @a denom_pub that is available (or was purged) 132 * @param bs_pub the public key itself, NULL if the key was revoked or purged 133 * @param sm_pub public key of the security module, NULL if the key was revoked or purged 134 * @param sm_sig signature from the security module, NULL if the key was revoked or purged 135 * The signature was already verified against @a sm_pub. 136 */ 137 static void 138 key_cb (void *cls, 139 const char *section_name, 140 struct GNUNET_TIME_Timestamp start_time, 141 struct GNUNET_TIME_Relative validity_duration, 142 const struct TALER_CsPubHashP *h_cs, 143 struct GNUNET_CRYPTO_BlindSignPublicKey *bs_pub, 144 const struct TALER_SecurityModulePublicKeyP *sm_pub, 145 const struct TALER_SecurityModuleSignatureP *sm_sig) 146 { 147 (void) cls; 148 (void) sm_pub; 149 (void) sm_sig; 150 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 151 "Key notification about key %s in `%s'\n", 152 GNUNET_h2s (&h_cs->hash), 153 section_name); 154 if (0 == validity_duration.rel_value_us) 155 { 156 bool found = false; 157 158 GNUNET_break (NULL == bs_pub); 159 GNUNET_break (NULL == section_name); 160 for (unsigned int i = 0; i<MAX_KEYS; i++) 161 if (0 == GNUNET_memcmp (h_cs, 162 &keys[i].h_cs)) 163 { 164 keys[i].valid = false; 165 keys[i].revoked = false; 166 TALER_denom_pub_free (&keys[i].denom_pub); 167 GNUNET_assert (num_keys > 0); 168 num_keys--; 169 found = true; 170 break; 171 } 172 if (! found) 173 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 174 "Error: helper announced expiration of unknown key!\n"); 175 176 return; 177 } 178 179 GNUNET_break (NULL != bs_pub); 180 for (unsigned int i = 0; i<MAX_KEYS; i++) 181 if (! keys[i].valid) 182 { 183 keys[i].valid = true; 184 keys[i].h_cs = *h_cs; 185 keys[i].start_time = start_time; 186 keys[i].validity_duration = validity_duration; 187 keys[i].denom_pub.bsign_pub_key 188 = GNUNET_CRYPTO_bsign_pub_incref (bs_pub); 189 num_keys++; 190 return; 191 } 192 /* too many keys! */ 193 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 194 "Error: received %d live keys from the service!\n", 195 MAX_KEYS + 1); 196 } 197 198 199 /** 200 * Test key revocation logic. 201 * 202 * @param dh handle to the helper 203 * @return 0 on success 204 */ 205 static int 206 test_revocation (struct TALER_CRYPTO_CsDenominationHelper *dh) 207 { 208 struct timespec req = { 209 .tv_nsec = 250000000 210 }; 211 212 for (unsigned int i = 0; i<NUM_REVOKES; i++) 213 { 214 uint32_t off; 215 216 off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 217 num_keys); 218 /* find index of key to revoke */ 219 for (unsigned int j = 0; j < MAX_KEYS; j++) 220 { 221 if (! keys[j].valid) 222 continue; 223 if (0 != off) 224 { 225 off--; 226 continue; 227 } 228 keys[j].revoked = true; 229 fprintf (stderr, 230 "Revoking key %s ...", 231 GNUNET_h2s (&keys[j].h_cs.hash)); 232 TALER_CRYPTO_helper_cs_revoke (dh, 233 &keys[j].h_cs); 234 for (unsigned int k = 0; k<1000; k++) 235 { 236 TALER_CRYPTO_helper_cs_poll (dh); 237 if (! keys[j].revoked) 238 break; 239 nanosleep (&req, NULL); 240 fprintf (stderr, "."); 241 } 242 if (keys[j].revoked) 243 { 244 fprintf (stderr, 245 "\nFAILED: timeout trying to revoke key %u\n", 246 j); 247 TALER_CRYPTO_helper_cs_disconnect (dh); 248 return 2; 249 } 250 fprintf (stderr, "\n"); 251 break; 252 } 253 } 254 return 0; 255 } 256 257 258 /** 259 * Test R derivation logic. 260 * 261 * @param dh handle to the helper 262 * @return 0 on success 263 */ 264 static int 265 test_r_derive (struct TALER_CRYPTO_CsDenominationHelper *dh) 266 { 267 enum TALER_ErrorCode ec; 268 bool success = false; 269 struct TALER_PlanchetMasterSecretP ps; 270 struct TALER_CoinSpendPrivateKeyP coin_priv; 271 union GNUNET_CRYPTO_BlindingSecretP bks; 272 struct TALER_CoinPubHashP c_hash; 273 struct GNUNET_CRYPTO_BlindingInputValues bi = { 274 .cipher = GNUNET_CRYPTO_BSA_CS 275 }; 276 struct TALER_ExchangeBlindingValues alg_values = { 277 .blinding_inputs = &bi 278 }; 279 union GNUNET_CRYPTO_BlindSessionNonce nonce; 280 281 TALER_planchet_master_setup_random (&ps); 282 for (unsigned int i = 0; i<MAX_KEYS; i++) 283 { 284 struct TALER_PlanchetDetail pd; 285 286 if (! keys[i].valid) 287 continue; 288 GNUNET_assert (GNUNET_CRYPTO_BSA_CS == 289 keys[i].denom_pub.bsign_pub_key->cipher); 290 #pragma message "phase out TALER_cs_withdraw_nonce_derive" 291 TALER_cs_withdraw_nonce_derive ( 292 &ps, 293 &nonce.cs_nonce); 294 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 295 "Requesting R derivation with key %s\n", 296 GNUNET_h2s (&keys[i].h_cs.hash)); 297 { 298 struct TALER_CRYPTO_CsDeriveRequest cdr = { 299 .h_cs = &keys[i].h_cs, 300 .nonce = &nonce.cs_nonce 301 }; 302 303 ec = TALER_CRYPTO_helper_cs_r_derive ( 304 dh, 305 &cdr, 306 false, 307 &bi.details.cs_values); 308 } 309 switch (ec) 310 { 311 case TALER_EC_NONE: 312 if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_remaining ( 313 keys[i].start_time.abs_time), 314 >, 315 GNUNET_TIME_UNIT_SECONDS)) 316 { 317 /* key worked too early */ 318 GNUNET_break (0); 319 return 4; 320 } 321 if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_duration ( 322 keys[i].start_time.abs_time), 323 >, 324 keys[i].validity_duration)) 325 { 326 /* key worked too later */ 327 GNUNET_break (0); 328 return 5; 329 } 330 331 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 332 "Received valid R for key %s\n", 333 GNUNET_h2s (&keys[i].h_cs.hash)); 334 TALER_planchet_setup_coin_priv (&ps, 335 &alg_values, 336 &coin_priv); 337 TALER_planchet_blinding_secret_create (&ps, 338 &alg_values, 339 &bks); 340 GNUNET_assert (GNUNET_OK == 341 TALER_planchet_prepare (&keys[i].denom_pub, 342 &alg_values, 343 &bks, 344 &nonce, 345 &coin_priv, 346 NULL, /* no age commitment */ 347 &c_hash, 348 &pd)); 349 TALER_blinded_planchet_free (&pd.blinded_planchet); 350 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 351 "Successfully prepared planchet"); 352 success = true; 353 break; 354 case TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY: 355 /* This 'failure' is expected, we're testing also for the 356 error handling! */ 357 if ( (GNUNET_TIME_relative_is_zero ( 358 GNUNET_TIME_absolute_get_remaining ( 359 keys[i].start_time.abs_time))) && 360 (GNUNET_TIME_relative_cmp ( 361 GNUNET_TIME_absolute_get_duration ( 362 keys[i].start_time.abs_time), 363 <, 364 keys[i].validity_duration)) ) 365 { 366 /* key should have worked! */ 367 GNUNET_break (0); 368 return 6; 369 } 370 break; 371 default: 372 /* unexpected error */ 373 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 374 "Unexpected error %d\n", 375 ec); 376 return 7; 377 } 378 } 379 if (! success) 380 { 381 /* no valid key for signing found, also bad */ 382 GNUNET_break (0); 383 return 16; 384 } 385 386 /* check R derivation does not work if the key is unknown */ 387 { 388 struct TALER_CsPubHashP rnd; 389 struct GNUNET_CRYPTO_CSPublicRPairP crp; 390 struct TALER_CRYPTO_CsDeriveRequest cdr = { 391 .h_cs = &rnd, 392 .nonce = &nonce.cs_nonce, 393 }; 394 395 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, 396 &rnd, 397 sizeof (rnd)); 398 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, 399 &nonce, 400 sizeof (nonce)); 401 ec = TALER_CRYPTO_helper_cs_r_derive (dh, 402 &cdr, 403 false, 404 &crp); 405 if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec) 406 { 407 GNUNET_break (0); 408 return 17; 409 } 410 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 411 "R derivation with invalid key %s failed as desired\n", 412 GNUNET_h2s (&rnd.hash)); 413 } 414 return 0; 415 } 416 417 418 /** 419 * Test signing logic. 420 * 421 * @param dh handle to the helper 422 * @return 0 on success 423 */ 424 static int 425 test_signing (struct TALER_CRYPTO_CsDenominationHelper *dh) 426 { 427 struct TALER_BlindedDenominationSignature ds; 428 enum TALER_ErrorCode ec; 429 bool success = false; 430 struct TALER_PlanchetMasterSecretP ps; 431 struct TALER_CoinSpendPrivateKeyP coin_priv; 432 union GNUNET_CRYPTO_BlindingSecretP bks; 433 struct TALER_CoinPubHashP c_hash; 434 struct GNUNET_CRYPTO_BlindingInputValues bi = { 435 .cipher = GNUNET_CRYPTO_BSA_CS 436 }; 437 struct TALER_ExchangeBlindingValues alg_values = { 438 .blinding_inputs = &bi 439 }; 440 union GNUNET_CRYPTO_BlindSessionNonce nonce; 441 442 TALER_planchet_master_setup_random (&ps); 443 for (unsigned int i = 0; i<MAX_KEYS; i++) 444 { 445 if (! keys[i].valid) 446 continue; 447 { 448 struct TALER_PlanchetDetail pd; 449 struct TALER_CRYPTO_CsSignRequest csr; 450 struct TALER_CRYPTO_CsDeriveRequest cdr = { 451 .h_cs = &keys[i].h_cs, 452 .nonce = &nonce.cs_nonce 453 }; 454 455 TALER_cs_withdraw_nonce_derive (&ps, 456 &nonce.cs_nonce); 457 ec = TALER_CRYPTO_helper_cs_r_derive ( 458 dh, 459 &cdr, 460 false, 461 &bi.details.cs_values); 462 if (TALER_EC_NONE != ec) 463 continue; 464 TALER_planchet_setup_coin_priv (&ps, 465 &alg_values, 466 &coin_priv); 467 TALER_planchet_blinding_secret_create (&ps, 468 &alg_values, 469 &bks); 470 GNUNET_assert (GNUNET_YES == 471 TALER_planchet_prepare (&keys[i].denom_pub, 472 &alg_values, 473 &bks, 474 &nonce, 475 &coin_priv, 476 NULL, /* no age commitment */ 477 &c_hash, 478 &pd)); 479 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 480 "Requesting signature with key %s\n", 481 GNUNET_h2s (&keys[i].h_cs.hash)); 482 csr.h_cs = &keys[i].h_cs; 483 csr.blinded_planchet 484 = &pd.blinded_planchet.blinded_message->details.cs_blinded_message; 485 ec = TALER_CRYPTO_helper_cs_sign ( 486 dh, 487 &csr, 488 false, 489 &ds); 490 TALER_blinded_planchet_free (&pd.blinded_planchet); 491 } 492 switch (ec) 493 { 494 case TALER_EC_NONE: 495 if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_remaining ( 496 keys[i].start_time.abs_time), 497 >, 498 GNUNET_TIME_UNIT_SECONDS)) 499 { 500 /* key worked too early */ 501 GNUNET_break (0); 502 TALER_blinded_denom_sig_free (&ds); 503 return 4; 504 } 505 if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_duration ( 506 keys[i].start_time.abs_time), 507 >, 508 keys[i].validity_duration)) 509 { 510 /* key worked too later */ 511 GNUNET_break (0); 512 TALER_blinded_denom_sig_free (&ds); 513 return 5; 514 } 515 { 516 struct TALER_FreshCoin coin; 517 518 if (GNUNET_OK != 519 TALER_planchet_to_coin (&keys[i].denom_pub, 520 &ds, 521 &bks, 522 &coin_priv, 523 NULL, /* no age commitment */ 524 &c_hash, 525 &alg_values, 526 &coin)) 527 { 528 GNUNET_break (0); 529 TALER_blinded_denom_sig_free (&ds); 530 return 6; 531 } 532 TALER_blinded_denom_sig_free (&ds); 533 TALER_denom_sig_free (&coin.sig); 534 } 535 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 536 "Received valid signature for key %s\n", 537 GNUNET_h2s (&keys[i].h_cs.hash)); 538 success = true; 539 break; 540 case TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY: 541 /* This 'failure' is expected, we're testing also for the 542 error handling! */ 543 if ( (GNUNET_TIME_relative_is_zero ( 544 GNUNET_TIME_absolute_get_remaining ( 545 keys[i].start_time.abs_time))) && 546 (GNUNET_TIME_relative_cmp ( 547 GNUNET_TIME_absolute_get_duration ( 548 keys[i].start_time.abs_time), 549 <, 550 keys[i].validity_duration)) ) 551 { 552 /* key should have worked! */ 553 GNUNET_break (0); 554 return 6; 555 } 556 break; 557 default: 558 /* unexpected error */ 559 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 560 "Unexpected error %d\n", 561 ec); 562 return 7; 563 } 564 } 565 if (! success) 566 { 567 /* no valid key for signing found, also bad */ 568 GNUNET_break (0); 569 return 16; 570 } 571 572 /* check signing does not work if the key is unknown */ 573 { 574 struct TALER_PlanchetDetail pd; 575 struct TALER_CsPubHashP rnd; 576 struct TALER_CRYPTO_CsSignRequest csr; 577 578 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, 579 &rnd, 580 sizeof (rnd)); 581 GNUNET_assert (GNUNET_YES == 582 TALER_planchet_prepare (&keys[0].denom_pub, 583 &alg_values, 584 &bks, 585 &nonce, 586 &coin_priv, 587 NULL, /* no age commitment */ 588 &c_hash, 589 &pd)); 590 csr.h_cs = &rnd; 591 csr.blinded_planchet 592 = &pd.blinded_planchet.blinded_message->details.cs_blinded_message; 593 ec = TALER_CRYPTO_helper_cs_sign ( 594 dh, 595 &csr, 596 false, 597 &ds); 598 TALER_blinded_planchet_free (&pd.blinded_planchet); 599 if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec) 600 { 601 if (TALER_EC_NONE == ec) 602 TALER_blinded_denom_sig_free (&ds); 603 GNUNET_break (0); 604 return 17; 605 } 606 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 607 "Signing with invalid key %s failed as desired\n", 608 GNUNET_h2s (&rnd.hash)); 609 } 610 return 0; 611 } 612 613 614 /** 615 * Test batch signing logic. 616 * 617 * @param dh handle to the helper 618 * @param batch_size how large should the batch be 619 * @param check_sigs also check unknown key and signatures 620 * @return 0 on success 621 */ 622 static int 623 test_batch_signing (struct TALER_CRYPTO_CsDenominationHelper *dh, 624 unsigned int batch_size, 625 bool check_sigs) 626 { 627 struct TALER_BlindedDenominationSignature ds[batch_size]; 628 enum TALER_ErrorCode ec; 629 bool success = false; 630 struct TALER_PlanchetMasterSecretP ps[batch_size]; 631 struct TALER_CoinSpendPrivateKeyP coin_priv[batch_size]; 632 union GNUNET_CRYPTO_BlindingSecretP bks[batch_size]; 633 struct TALER_CoinPubHashP c_hash[batch_size]; 634 struct GNUNET_CRYPTO_BlindingInputValues bi[batch_size]; 635 struct TALER_ExchangeBlindingValues alg_values[batch_size]; 636 union GNUNET_CRYPTO_BlindSessionNonce nonces[batch_size]; 637 638 for (unsigned int i = 0; i<batch_size; i++) 639 TALER_planchet_master_setup_random (&ps[i]); 640 for (unsigned int k = 0; k<MAX_KEYS; k++) 641 { 642 if (! keys[k].valid) 643 continue; 644 { 645 struct TALER_PlanchetDetail pd[batch_size]; 646 struct TALER_CRYPTO_CsSignRequest csr[batch_size]; 647 struct TALER_CRYPTO_CsDeriveRequest cdr[batch_size]; 648 struct GNUNET_CRYPTO_CSPublicRPairP crps[batch_size]; 649 650 for (unsigned int i = 0; i<batch_size; i++) 651 { 652 cdr[i].h_cs = &keys[k].h_cs; 653 cdr[i].nonce = &nonces[i].cs_nonce; 654 TALER_cs_withdraw_nonce_derive ( 655 &ps[i], 656 &nonces[i].cs_nonce); 657 bi[i].cipher = GNUNET_CRYPTO_BSA_CS; 658 alg_values[i].blinding_inputs = &bi[i]; 659 } 660 ec = TALER_CRYPTO_helper_cs_r_batch_derive ( 661 dh, 662 batch_size, 663 cdr, 664 false, 665 crps); 666 if (TALER_EC_NONE != ec) 667 continue; 668 for (unsigned int i = 0; i<batch_size; i++) 669 { 670 bi[i].details.cs_values = crps[i]; 671 TALER_planchet_setup_coin_priv (&ps[i], 672 &alg_values[i], 673 &coin_priv[i]); 674 TALER_planchet_blinding_secret_create (&ps[i], 675 &alg_values[i], 676 &bks[i]); 677 GNUNET_assert (GNUNET_YES == 678 TALER_planchet_prepare (&keys[k].denom_pub, 679 &alg_values[i], 680 &bks[i], 681 &nonces[i], 682 &coin_priv[i], 683 NULL, /* no age commitment */ 684 &c_hash[i], 685 &pd[i])); 686 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 687 "Requesting signature with key %s\n", 688 GNUNET_h2s (&keys[k].h_cs.hash)); 689 csr[i].h_cs = &keys[k].h_cs; 690 csr[i].blinded_planchet 691 = &pd[i].blinded_planchet.blinded_message->details.cs_blinded_message; 692 } 693 ec = TALER_CRYPTO_helper_cs_batch_sign ( 694 dh, 695 batch_size, 696 csr, 697 false, 698 ds); 699 for (unsigned int i = 0; i<batch_size; i++) 700 { 701 TALER_blinded_planchet_free (&pd[i].blinded_planchet); 702 } 703 } 704 switch (ec) 705 { 706 case TALER_EC_NONE: 707 if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_remaining ( 708 keys[k].start_time.abs_time), 709 >, 710 GNUNET_TIME_UNIT_SECONDS)) 711 { 712 /* key worked too early */ 713 GNUNET_break (0); 714 return 4; 715 } 716 if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_duration ( 717 keys[k].start_time.abs_time), 718 >, 719 keys[k].validity_duration)) 720 { 721 /* key worked too later */ 722 GNUNET_break (0); 723 return 5; 724 } 725 if (check_sigs) 726 { 727 for (unsigned int i = 0; i<batch_size; i++) 728 { 729 struct TALER_FreshCoin coin; 730 731 if (GNUNET_OK != 732 TALER_planchet_to_coin (&keys[k].denom_pub, 733 &ds[i], 734 &bks[i], 735 &coin_priv[i], 736 NULL, /* no age commitment */ 737 &c_hash[i], 738 &alg_values[i], 739 &coin)) 740 { 741 GNUNET_break (0); 742 return 6; 743 } 744 TALER_blinded_denom_sig_free (&ds[i]); 745 TALER_denom_sig_free (&coin.sig); 746 } 747 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 748 "Received valid signature for key %s\n", 749 GNUNET_h2s (&keys[k].h_cs.hash)); 750 } 751 else 752 { 753 for (unsigned int i = 0; i<batch_size; i++) 754 TALER_blinded_denom_sig_free (&ds[i]); 755 } 756 success = true; 757 break; 758 case TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY: 759 /* This 'failure' is expected, we're testing also for the 760 error handling! */ 761 if ( (GNUNET_TIME_relative_is_zero ( 762 GNUNET_TIME_absolute_get_remaining ( 763 keys[k].start_time.abs_time))) && 764 (GNUNET_TIME_relative_cmp ( 765 GNUNET_TIME_absolute_get_duration ( 766 keys[k].start_time.abs_time), 767 <, 768 keys[k].validity_duration)) ) 769 { 770 /* key should have worked! */ 771 GNUNET_break (0); 772 return 6; 773 } 774 break; 775 default: 776 /* unexpected error */ 777 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 778 "Unexpected error %d\n", 779 ec); 780 return 7; 781 } 782 } 783 if (! success) 784 { 785 /* no valid key for signing found, also bad */ 786 GNUNET_break (0); 787 return 16; 788 } 789 790 /* check signing does not work if the key is unknown */ 791 if (check_sigs) 792 { 793 struct TALER_PlanchetDetail pd; 794 struct TALER_CsPubHashP rnd; 795 struct TALER_CRYPTO_CsSignRequest csr; 796 797 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, 798 &rnd, 799 sizeof (rnd)); 800 GNUNET_assert (GNUNET_YES == 801 TALER_planchet_prepare (&keys[0].denom_pub, 802 &alg_values[0], 803 &bks[0], 804 &nonces[0], 805 &coin_priv[0], 806 NULL, /* no age commitment */ 807 &c_hash[0], 808 &pd)); 809 csr.h_cs = &rnd; 810 csr.blinded_planchet 811 = &pd.blinded_planchet.blinded_message->details.cs_blinded_message; 812 ec = TALER_CRYPTO_helper_cs_batch_sign ( 813 dh, 814 1, 815 &csr, 816 false, 817 &ds[0]); 818 TALER_blinded_planchet_free (&pd.blinded_planchet); 819 if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec) 820 { 821 if (TALER_EC_NONE == ec) 822 TALER_blinded_denom_sig_free (&ds[0]); 823 GNUNET_break (0); 824 return 17; 825 } 826 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 827 "Signing with invalid key %s failed as desired\n", 828 GNUNET_h2s (&rnd.hash)); 829 } 830 return 0; 831 } 832 833 834 /** 835 * Benchmark signing logic. 836 * 837 * @param dh handle to the helper 838 * @return 0 on success 839 */ 840 static int 841 perf_signing (struct TALER_CRYPTO_CsDenominationHelper *dh, 842 const char *type) 843 { 844 struct TALER_BlindedDenominationSignature ds; 845 enum TALER_ErrorCode ec; 846 struct GNUNET_TIME_Relative duration; 847 struct TALER_PlanchetMasterSecretP ps; 848 struct TALER_CoinSpendPrivateKeyP coin_priv; 849 union GNUNET_CRYPTO_BlindingSecretP bks; 850 struct GNUNET_CRYPTO_BlindingInputValues bv = { 851 .cipher = GNUNET_CRYPTO_BSA_CS 852 }; 853 struct TALER_ExchangeBlindingValues alg_values = { 854 .blinding_inputs = &bv 855 }; 856 857 TALER_planchet_master_setup_random (&ps); 858 duration = GNUNET_TIME_UNIT_ZERO; 859 TALER_CRYPTO_helper_cs_poll (dh); 860 for (unsigned int j = 0; j<NUM_SIGN_PERFS;) 861 { 862 for (unsigned int i = 0; i<MAX_KEYS; i++) 863 { 864 if (! keys[i].valid) 865 continue; 866 if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_remaining ( 867 keys[i].start_time.abs_time), 868 >, 869 GNUNET_TIME_UNIT_SECONDS)) 870 continue; 871 if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_duration ( 872 keys[i].start_time.abs_time), 873 >, 874 keys[i].validity_duration)) 875 continue; 876 { 877 struct TALER_CoinPubHashP c_hash; 878 struct TALER_PlanchetDetail pd; 879 union GNUNET_CRYPTO_BlindSessionNonce nonce; 880 struct TALER_CRYPTO_CsDeriveRequest cdr = { 881 .h_cs = &keys[i].h_cs, 882 .nonce = &nonce.cs_nonce 883 }; 884 885 TALER_cs_withdraw_nonce_derive ( 886 &ps, 887 &nonce.cs_nonce); 888 ec = TALER_CRYPTO_helper_cs_r_derive ( 889 dh, 890 &cdr, 891 true, 892 &bv.details.cs_values); 893 if (TALER_EC_NONE != ec) 894 continue; 895 TALER_planchet_setup_coin_priv (&ps, 896 &alg_values, 897 &coin_priv); 898 TALER_planchet_blinding_secret_create (&ps, 899 &alg_values, 900 &bks); 901 GNUNET_assert (GNUNET_YES == 902 TALER_planchet_prepare (&keys[i].denom_pub, 903 &alg_values, 904 &bks, 905 &nonce, 906 &coin_priv, 907 NULL, /* no age commitment */ 908 &c_hash, 909 &pd)); 910 /* use this key as long as it works */ 911 while (1) 912 { 913 struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get (); 914 struct GNUNET_TIME_Relative delay; 915 struct TALER_CRYPTO_CsSignRequest csr; 916 917 csr.h_cs = &keys[i].h_cs; 918 csr.blinded_planchet 919 = &pd.blinded_planchet.blinded_message->details.cs_blinded_message; 920 ec = TALER_CRYPTO_helper_cs_sign ( 921 dh, 922 &csr, 923 true, 924 &ds); 925 if (TALER_EC_NONE != ec) 926 break; 927 delay = GNUNET_TIME_absolute_get_duration (start); 928 duration = GNUNET_TIME_relative_add (duration, 929 delay); 930 TALER_blinded_denom_sig_free (&ds); 931 j++; 932 if (NUM_SIGN_PERFS <= j) 933 break; 934 } 935 TALER_blinded_planchet_free (&pd.blinded_planchet); 936 } 937 } /* for i */ 938 } /* for j */ 939 fprintf (stderr, 940 "%u (%s) signature operations took %s\n", 941 (unsigned int) NUM_SIGN_PERFS, 942 type, 943 GNUNET_STRINGS_relative_time_to_string (duration, 944 GNUNET_YES)); 945 return 0; 946 } 947 948 949 /** 950 * Parallel signing logic. 951 * 952 * @param esh handle to the helper 953 * @return 0 on success 954 */ 955 static int 956 par_signing (struct GNUNET_CONFIGURATION_Handle *cfg) 957 { 958 struct GNUNET_TIME_Absolute start; 959 struct GNUNET_TIME_Relative duration; 960 pid_t pids[NUM_CORES]; 961 struct TALER_CRYPTO_CsDenominationHelper *dh; 962 963 start = GNUNET_TIME_absolute_get (); 964 for (unsigned int i = 0; i<NUM_CORES; i++) 965 { 966 pids[i] = fork (); 967 num_keys = 0; 968 GNUNET_assert (-1 != pids[i]); 969 if (0 == pids[i]) 970 { 971 int ret; 972 973 dh = TALER_CRYPTO_helper_cs_connect (cfg, 974 "taler-exchange", 975 &key_cb, 976 NULL); 977 GNUNET_assert (NULL != dh); 978 ret = perf_signing (dh, 979 "parallel"); 980 TALER_CRYPTO_helper_cs_disconnect (dh); 981 free_keys (); 982 exit (ret); 983 } 984 } 985 for (unsigned int i = 0; i<NUM_CORES; i++) 986 { 987 int wstatus; 988 989 GNUNET_assert (pids[i] == 990 waitpid (pids[i], 991 &wstatus, 992 0)); 993 } 994 duration = GNUNET_TIME_absolute_get_duration (start); 995 fprintf (stderr, 996 "%u (parallel) signature operations took %s (total real time)\n", 997 (unsigned int) NUM_SIGN_PERFS * NUM_CORES, 998 GNUNET_STRINGS_relative_time_to_string (duration, 999 GNUNET_YES)); 1000 return 0; 1001 } 1002 1003 1004 /** 1005 * Main entry point into the test logic with the helper already running. 1006 */ 1007 static int 1008 run_test (void) 1009 { 1010 struct GNUNET_CONFIGURATION_Handle *cfg; 1011 struct TALER_CRYPTO_CsDenominationHelper *dh; 1012 struct timespec req = { 1013 .tv_nsec = 250000000 1014 }; 1015 int ret; 1016 1017 cfg = GNUNET_CONFIGURATION_create (TALER_EXCHANGE_project_data ()); 1018 if (GNUNET_OK != 1019 GNUNET_CONFIGURATION_load (cfg, 1020 "test_helper_cs.conf")) 1021 { 1022 GNUNET_break (0); 1023 return 77; 1024 } 1025 1026 fprintf (stderr, "Waiting for helper to start ... "); 1027 for (unsigned int i = 0; i<100; i++) 1028 { 1029 nanosleep (&req, 1030 NULL); 1031 dh = TALER_CRYPTO_helper_cs_connect (cfg, 1032 "taler-exchange", 1033 &key_cb, 1034 NULL); 1035 if (NULL != dh) 1036 break; 1037 fprintf (stderr, "."); 1038 } 1039 if (NULL == dh) 1040 { 1041 fprintf (stderr, 1042 "\nFAILED: timeout trying to connect to helper\n"); 1043 GNUNET_CONFIGURATION_destroy (cfg); 1044 return 1; 1045 } 1046 if (0 == num_keys) 1047 { 1048 fprintf (stderr, 1049 "\nFAILED: timeout trying to connect to helper\n"); 1050 TALER_CRYPTO_helper_cs_disconnect (dh); 1051 GNUNET_CONFIGURATION_destroy (cfg); 1052 return 1; 1053 } 1054 fprintf (stderr, 1055 " Done (%u keys)\n", 1056 num_keys); 1057 ret = 0; 1058 if (0 == ret) 1059 ret = test_revocation (dh); 1060 if (0 == ret) 1061 ret = test_r_derive (dh); 1062 if (0 == ret) 1063 ret = test_signing (dh); 1064 if (0 == ret) 1065 ret = test_batch_signing (dh, 1066 2, 1067 true); 1068 if (0 == ret) 1069 ret = test_batch_signing (dh, 1070 64, 1071 true); 1072 for (unsigned int i = 0; i<4; i++) 1073 { 1074 static unsigned int batches[] = { 1, 4, 16, 64 }; 1075 unsigned int batch_size = batches[i]; 1076 struct GNUNET_TIME_Absolute start; 1077 struct GNUNET_TIME_Relative duration; 1078 1079 start = GNUNET_TIME_absolute_get (); 1080 if (0 != ret) 1081 break; 1082 ret = test_batch_signing (dh, 1083 batch_size, 1084 false); 1085 duration = GNUNET_TIME_absolute_get_duration (start); 1086 fprintf (stderr, 1087 "%4u (batch) signature operations took %s (total real time)\n", 1088 (unsigned int) batch_size, 1089 GNUNET_STRINGS_relative_time_to_string (duration, 1090 GNUNET_YES)); 1091 } 1092 if (0 == ret) 1093 ret = perf_signing (dh, 1094 "sequential"); 1095 TALER_CRYPTO_helper_cs_disconnect (dh); 1096 free_keys (); 1097 if (0 == ret) 1098 ret = par_signing (cfg); 1099 /* clean up our state */ 1100 GNUNET_CONFIGURATION_destroy (cfg); 1101 return ret; 1102 } 1103 1104 1105 int 1106 main (int argc, 1107 const char *const argv[]) 1108 { 1109 struct GNUNET_OS_Process *helper; 1110 char *libexec_dir; 1111 char *binary_name; 1112 int ret; 1113 enum GNUNET_OS_ProcessStatusType type; 1114 unsigned long code; 1115 const char *loglev = "WARNING"; 1116 1117 (void) argc; 1118 (void) argv; 1119 unsetenv ("XDG_DATA_HOME"); 1120 unsetenv ("XDG_CONFIG_HOME"); 1121 GNUNET_log_setup ("test-helper-cs", 1122 loglev, 1123 NULL); 1124 libexec_dir = GNUNET_OS_installation_get_path (TALER_EXCHANGE_project_data (), 1125 GNUNET_OS_IPK_BINDIR); 1126 GNUNET_asprintf (&binary_name, 1127 "%s/%s", 1128 libexec_dir, 1129 "taler-exchange-secmod-cs"); 1130 GNUNET_free (libexec_dir); 1131 helper = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ERR, 1132 NULL, NULL, NULL, 1133 binary_name, 1134 binary_name, 1135 "-c", 1136 "test_helper_cs.conf", 1137 "-L", 1138 loglev, 1139 NULL); 1140 if (NULL == helper) 1141 { 1142 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 1143 "exec", 1144 binary_name); 1145 GNUNET_free (binary_name); 1146 return 77; 1147 } 1148 GNUNET_free (binary_name); 1149 ret = run_test (); 1150 1151 GNUNET_OS_process_kill (helper, 1152 SIGTERM); 1153 if (GNUNET_OK != 1154 GNUNET_OS_process_wait_status (helper, 1155 &type, 1156 &code)) 1157 { 1158 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1159 "Helper process did not die voluntarily, killing hard\n"); 1160 GNUNET_OS_process_kill (helper, 1161 SIGKILL); 1162 ret = 4; 1163 } 1164 else if ( (GNUNET_OS_PROCESS_EXITED != type) || 1165 (0 != code) ) 1166 { 1167 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1168 "Helper died with unexpected status %d/%d\n", 1169 (int) type, 1170 (int) code); 1171 ret = 5; 1172 } 1173 GNUNET_OS_process_destroy (helper); 1174 return ret; 1175 } 1176 1177 1178 /* end of test_helper_cs.c */