test_helper_cs.c (36920B)
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 "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_batch_derive ( 304 dh, 305 1, 306 &cdr, 307 false, 308 &bi.details.cs_values); 309 } 310 switch (ec) 311 { 312 case TALER_EC_NONE: 313 if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_remaining ( 314 keys[i].start_time.abs_time), 315 >, 316 GNUNET_TIME_UNIT_SECONDS)) 317 { 318 /* key worked too early */ 319 GNUNET_break (0); 320 return 4; 321 } 322 if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_duration ( 323 keys[i].start_time.abs_time), 324 >, 325 keys[i].validity_duration)) 326 { 327 /* key worked too later */ 328 GNUNET_break (0); 329 return 5; 330 } 331 332 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 333 "Received valid R for key %s\n", 334 GNUNET_h2s (&keys[i].h_cs.hash)); 335 TALER_planchet_setup_coin_priv (&ps, 336 &alg_values, 337 &coin_priv); 338 TALER_planchet_blinding_secret_create (&ps, 339 &alg_values, 340 &bks); 341 GNUNET_assert (GNUNET_OK == 342 TALER_planchet_prepare (&keys[i].denom_pub, 343 &alg_values, 344 &bks, 345 &nonce, 346 &coin_priv, 347 NULL, /* no age commitment */ 348 &c_hash, 349 &pd)); 350 TALER_blinded_planchet_free (&pd.blinded_planchet); 351 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 352 "Successfully prepared planchet"); 353 success = true; 354 break; 355 case TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY: 356 /* This 'failure' is expected, we're testing also for the 357 error handling! */ 358 if ( (GNUNET_TIME_relative_is_zero ( 359 GNUNET_TIME_absolute_get_remaining ( 360 keys[i].start_time.abs_time))) && 361 (GNUNET_TIME_relative_cmp ( 362 GNUNET_TIME_absolute_get_duration ( 363 keys[i].start_time.abs_time), 364 <, 365 keys[i].validity_duration)) ) 366 { 367 /* key should have worked! */ 368 GNUNET_break (0); 369 return 6; 370 } 371 break; 372 default: 373 /* unexpected error */ 374 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 375 "Unexpected error %d\n", 376 ec); 377 return 7; 378 } 379 } 380 if (! success) 381 { 382 /* no valid key for signing found, also bad */ 383 GNUNET_break (0); 384 return 16; 385 } 386 387 /* check R derivation does not work if the key is unknown */ 388 { 389 struct TALER_CsPubHashP rnd; 390 struct GNUNET_CRYPTO_CSPublicRPairP crp; 391 struct TALER_CRYPTO_CsDeriveRequest cdr = { 392 .h_cs = &rnd, 393 .nonce = &nonce.cs_nonce, 394 }; 395 396 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, 397 &rnd, 398 sizeof (rnd)); 399 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, 400 &nonce, 401 sizeof (nonce)); 402 ec = TALER_CRYPTO_helper_cs_r_batch_derive (dh, 403 1, 404 &cdr, 405 false, 406 &crp); 407 if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec) 408 { 409 GNUNET_break (0); 410 return 17; 411 } 412 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 413 "R derivation with invalid key %s failed as desired\n", 414 GNUNET_h2s (&rnd.hash)); 415 } 416 return 0; 417 } 418 419 420 /** 421 * Test signing logic. 422 * 423 * @param dh handle to the helper 424 * @return 0 on success 425 */ 426 static int 427 test_signing (struct TALER_CRYPTO_CsDenominationHelper *dh) 428 { 429 struct TALER_BlindedDenominationSignature ds; 430 enum TALER_ErrorCode ec; 431 bool success = false; 432 struct TALER_PlanchetMasterSecretP ps; 433 struct TALER_CoinSpendPrivateKeyP coin_priv; 434 union GNUNET_CRYPTO_BlindingSecretP bks; 435 struct TALER_CoinPubHashP c_hash; 436 struct GNUNET_CRYPTO_BlindingInputValues bi = { 437 .cipher = GNUNET_CRYPTO_BSA_CS 438 }; 439 struct TALER_ExchangeBlindingValues alg_values = { 440 .blinding_inputs = &bi 441 }; 442 union GNUNET_CRYPTO_BlindSessionNonce nonce; 443 444 TALER_planchet_master_setup_random (&ps); 445 for (unsigned int i = 0; i<MAX_KEYS; i++) 446 { 447 if (! keys[i].valid) 448 continue; 449 { 450 struct TALER_PlanchetDetail pd; 451 struct TALER_CRYPTO_CsSignRequest csr; 452 struct TALER_CRYPTO_CsDeriveRequest cdr = { 453 .h_cs = &keys[i].h_cs, 454 .nonce = &nonce.cs_nonce 455 }; 456 457 TALER_cs_withdraw_nonce_derive (&ps, 458 &nonce.cs_nonce); 459 ec = TALER_CRYPTO_helper_cs_r_batch_derive ( 460 dh, 461 1, 462 &cdr, 463 false, 464 &bi.details.cs_values); 465 if (TALER_EC_NONE != ec) 466 continue; 467 TALER_planchet_setup_coin_priv (&ps, 468 &alg_values, 469 &coin_priv); 470 TALER_planchet_blinding_secret_create (&ps, 471 &alg_values, 472 &bks); 473 GNUNET_assert (GNUNET_YES == 474 TALER_planchet_prepare (&keys[i].denom_pub, 475 &alg_values, 476 &bks, 477 &nonce, 478 &coin_priv, 479 NULL, /* no age commitment */ 480 &c_hash, 481 &pd)); 482 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 483 "Requesting signature with key %s\n", 484 GNUNET_h2s (&keys[i].h_cs.hash)); 485 csr.h_cs = &keys[i].h_cs; 486 csr.blinded_planchet 487 = &pd.blinded_planchet.blinded_message->details.cs_blinded_message; 488 ec = TALER_CRYPTO_helper_cs_batch_sign ( 489 dh, 490 1, 491 &csr, 492 false, 493 &ds); 494 TALER_blinded_planchet_free (&pd.blinded_planchet); 495 } 496 switch (ec) 497 { 498 case TALER_EC_NONE: 499 if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_remaining ( 500 keys[i].start_time.abs_time), 501 >, 502 GNUNET_TIME_UNIT_SECONDS)) 503 { 504 /* key worked too early */ 505 GNUNET_break (0); 506 TALER_blinded_denom_sig_free (&ds); 507 return 4; 508 } 509 if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_duration ( 510 keys[i].start_time.abs_time), 511 >, 512 keys[i].validity_duration)) 513 { 514 /* key worked too later */ 515 GNUNET_break (0); 516 TALER_blinded_denom_sig_free (&ds); 517 return 5; 518 } 519 { 520 struct TALER_FreshCoin coin; 521 522 if (GNUNET_OK != 523 TALER_planchet_to_coin (&keys[i].denom_pub, 524 &ds, 525 &bks, 526 &coin_priv, 527 NULL, /* no age commitment */ 528 &c_hash, 529 &alg_values, 530 &coin)) 531 { 532 GNUNET_break (0); 533 TALER_blinded_denom_sig_free (&ds); 534 return 6; 535 } 536 TALER_blinded_denom_sig_free (&ds); 537 TALER_denom_sig_free (&coin.sig); 538 } 539 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 540 "Received valid signature for key %s\n", 541 GNUNET_h2s (&keys[i].h_cs.hash)); 542 success = true; 543 break; 544 case TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY: 545 /* This 'failure' is expected, we're testing also for the 546 error handling! */ 547 if ( (GNUNET_TIME_relative_is_zero ( 548 GNUNET_TIME_absolute_get_remaining ( 549 keys[i].start_time.abs_time))) && 550 (GNUNET_TIME_relative_cmp ( 551 GNUNET_TIME_absolute_get_duration ( 552 keys[i].start_time.abs_time), 553 <, 554 keys[i].validity_duration)) ) 555 { 556 /* key should have worked! */ 557 GNUNET_break (0); 558 return 6; 559 } 560 break; 561 default: 562 /* unexpected error */ 563 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 564 "Unexpected error %d\n", 565 ec); 566 return 7; 567 } 568 } 569 if (! success) 570 { 571 /* no valid key for signing found, also bad */ 572 GNUNET_break (0); 573 return 16; 574 } 575 576 /* check signing does not work if the key is unknown */ 577 { 578 struct TALER_PlanchetDetail pd; 579 struct TALER_CsPubHashP rnd; 580 struct TALER_CRYPTO_CsSignRequest csr; 581 582 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, 583 &rnd, 584 sizeof (rnd)); 585 GNUNET_assert (GNUNET_YES == 586 TALER_planchet_prepare (&keys[0].denom_pub, 587 &alg_values, 588 &bks, 589 &nonce, 590 &coin_priv, 591 NULL, /* no age commitment */ 592 &c_hash, 593 &pd)); 594 csr.h_cs = &rnd; 595 csr.blinded_planchet 596 = &pd.blinded_planchet.blinded_message->details.cs_blinded_message; 597 ec = TALER_CRYPTO_helper_cs_batch_sign ( 598 dh, 599 1, 600 &csr, 601 false, 602 &ds); 603 TALER_blinded_planchet_free (&pd.blinded_planchet); 604 if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec) 605 { 606 if (TALER_EC_NONE == ec) 607 TALER_blinded_denom_sig_free (&ds); 608 GNUNET_break (0); 609 return 17; 610 } 611 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 612 "Signing with invalid key %s failed as desired\n", 613 GNUNET_h2s (&rnd.hash)); 614 } 615 return 0; 616 } 617 618 619 /** 620 * Test batch signing logic. 621 * 622 * @param dh handle to the helper 623 * @param batch_size how large should the batch be 624 * @param check_sigs also check unknown key and signatures 625 * @return 0 on success 626 */ 627 static int 628 test_batch_signing (struct TALER_CRYPTO_CsDenominationHelper *dh, 629 unsigned int batch_size, 630 bool check_sigs) 631 { 632 struct TALER_BlindedDenominationSignature ds[batch_size]; 633 enum TALER_ErrorCode ec; 634 bool success = false; 635 struct TALER_PlanchetMasterSecretP ps[batch_size]; 636 struct TALER_CoinSpendPrivateKeyP coin_priv[batch_size]; 637 union GNUNET_CRYPTO_BlindingSecretP bks[batch_size]; 638 struct TALER_CoinPubHashP c_hash[batch_size]; 639 struct GNUNET_CRYPTO_BlindingInputValues bi[batch_size]; 640 struct TALER_ExchangeBlindingValues alg_values[batch_size]; 641 union GNUNET_CRYPTO_BlindSessionNonce nonces[batch_size]; 642 643 for (unsigned int i = 0; i<batch_size; i++) 644 TALER_planchet_master_setup_random (&ps[i]); 645 for (unsigned int k = 0; k<MAX_KEYS; k++) 646 { 647 if (! keys[k].valid) 648 continue; 649 { 650 struct TALER_PlanchetDetail pd[batch_size]; 651 struct TALER_CRYPTO_CsSignRequest csr[batch_size]; 652 struct TALER_CRYPTO_CsDeriveRequest cdr[batch_size]; 653 struct GNUNET_CRYPTO_CSPublicRPairP crps[batch_size]; 654 655 for (unsigned int i = 0; i<batch_size; i++) 656 { 657 cdr[i].h_cs = &keys[k].h_cs; 658 cdr[i].nonce = &nonces[i].cs_nonce; 659 TALER_cs_withdraw_nonce_derive ( 660 &ps[i], 661 &nonces[i].cs_nonce); 662 bi[i].cipher = GNUNET_CRYPTO_BSA_CS; 663 alg_values[i].blinding_inputs = &bi[i]; 664 } 665 ec = TALER_CRYPTO_helper_cs_r_batch_derive ( 666 dh, 667 batch_size, 668 cdr, 669 false, 670 crps); 671 if (TALER_EC_NONE != ec) 672 continue; 673 for (unsigned int i = 0; i<batch_size; i++) 674 { 675 bi[i].details.cs_values = crps[i]; 676 TALER_planchet_setup_coin_priv (&ps[i], 677 &alg_values[i], 678 &coin_priv[i]); 679 TALER_planchet_blinding_secret_create (&ps[i], 680 &alg_values[i], 681 &bks[i]); 682 GNUNET_assert (GNUNET_YES == 683 TALER_planchet_prepare (&keys[k].denom_pub, 684 &alg_values[i], 685 &bks[i], 686 &nonces[i], 687 &coin_priv[i], 688 NULL, /* no age commitment */ 689 &c_hash[i], 690 &pd[i])); 691 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 692 "Requesting signature with key %s\n", 693 GNUNET_h2s (&keys[k].h_cs.hash)); 694 csr[i].h_cs = &keys[k].h_cs; 695 csr[i].blinded_planchet 696 = &pd[i].blinded_planchet.blinded_message->details.cs_blinded_message; 697 } 698 ec = TALER_CRYPTO_helper_cs_batch_sign ( 699 dh, 700 batch_size, 701 csr, 702 false, 703 ds); 704 for (unsigned int i = 0; i<batch_size; i++) 705 { 706 TALER_blinded_planchet_free (&pd[i].blinded_planchet); 707 } 708 } 709 switch (ec) 710 { 711 case TALER_EC_NONE: 712 if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_remaining ( 713 keys[k].start_time.abs_time), 714 >, 715 GNUNET_TIME_UNIT_SECONDS)) 716 { 717 /* key worked too early */ 718 GNUNET_break (0); 719 return 4; 720 } 721 if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_duration ( 722 keys[k].start_time.abs_time), 723 >, 724 keys[k].validity_duration)) 725 { 726 /* key worked too later */ 727 GNUNET_break (0); 728 return 5; 729 } 730 if (check_sigs) 731 { 732 for (unsigned int i = 0; i<batch_size; i++) 733 { 734 struct TALER_FreshCoin coin; 735 736 if (GNUNET_OK != 737 TALER_planchet_to_coin (&keys[k].denom_pub, 738 &ds[i], 739 &bks[i], 740 &coin_priv[i], 741 NULL, /* no age commitment */ 742 &c_hash[i], 743 &alg_values[i], 744 &coin)) 745 { 746 GNUNET_break (0); 747 return 6; 748 } 749 TALER_blinded_denom_sig_free (&ds[i]); 750 TALER_denom_sig_free (&coin.sig); 751 } 752 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 753 "Received valid signature for key %s\n", 754 GNUNET_h2s (&keys[k].h_cs.hash)); 755 } 756 else 757 { 758 for (unsigned int i = 0; i<batch_size; i++) 759 TALER_blinded_denom_sig_free (&ds[i]); 760 } 761 success = true; 762 break; 763 case TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY: 764 /* This 'failure' is expected, we're testing also for the 765 error handling! */ 766 if ( (GNUNET_TIME_relative_is_zero ( 767 GNUNET_TIME_absolute_get_remaining ( 768 keys[k].start_time.abs_time))) && 769 (GNUNET_TIME_relative_cmp ( 770 GNUNET_TIME_absolute_get_duration ( 771 keys[k].start_time.abs_time), 772 <, 773 keys[k].validity_duration)) ) 774 { 775 /* key should have worked! */ 776 GNUNET_break (0); 777 return 6; 778 } 779 break; 780 default: 781 /* unexpected error */ 782 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 783 "Unexpected error %d\n", 784 ec); 785 return 7; 786 } 787 } 788 if (! success) 789 { 790 /* no valid key for signing found, also bad */ 791 GNUNET_break (0); 792 return 16; 793 } 794 795 /* check signing does not work if the key is unknown */ 796 if (check_sigs) 797 { 798 struct TALER_PlanchetDetail pd; 799 struct TALER_CsPubHashP rnd; 800 struct TALER_CRYPTO_CsSignRequest csr; 801 802 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, 803 &rnd, 804 sizeof (rnd)); 805 GNUNET_assert (GNUNET_YES == 806 TALER_planchet_prepare (&keys[0].denom_pub, 807 &alg_values[0], 808 &bks[0], 809 &nonces[0], 810 &coin_priv[0], 811 NULL, /* no age commitment */ 812 &c_hash[0], 813 &pd)); 814 csr.h_cs = &rnd; 815 csr.blinded_planchet 816 = &pd.blinded_planchet.blinded_message->details.cs_blinded_message; 817 ec = TALER_CRYPTO_helper_cs_batch_sign ( 818 dh, 819 1, 820 &csr, 821 false, 822 &ds[0]); 823 TALER_blinded_planchet_free (&pd.blinded_planchet); 824 if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec) 825 { 826 if (TALER_EC_NONE == ec) 827 TALER_blinded_denom_sig_free (&ds[0]); 828 GNUNET_break (0); 829 return 17; 830 } 831 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 832 "Signing with invalid key %s failed as desired\n", 833 GNUNET_h2s (&rnd.hash)); 834 } 835 return 0; 836 } 837 838 839 /** 840 * Benchmark signing logic. 841 * 842 * @param dh handle to the helper 843 * @return 0 on success 844 */ 845 static int 846 perf_signing (struct TALER_CRYPTO_CsDenominationHelper *dh, 847 const char *type) 848 { 849 struct TALER_BlindedDenominationSignature ds; 850 enum TALER_ErrorCode ec; 851 struct GNUNET_TIME_Relative duration; 852 struct TALER_PlanchetMasterSecretP ps; 853 struct TALER_CoinSpendPrivateKeyP coin_priv; 854 union GNUNET_CRYPTO_BlindingSecretP bks; 855 struct GNUNET_CRYPTO_BlindingInputValues bv = { 856 .cipher = GNUNET_CRYPTO_BSA_CS 857 }; 858 struct TALER_ExchangeBlindingValues alg_values = { 859 .blinding_inputs = &bv 860 }; 861 862 TALER_planchet_master_setup_random (&ps); 863 duration = GNUNET_TIME_UNIT_ZERO; 864 TALER_CRYPTO_helper_cs_poll (dh); 865 for (unsigned int j = 0; j<NUM_SIGN_PERFS;) 866 { 867 for (unsigned int i = 0; i<MAX_KEYS; i++) 868 { 869 if (! keys[i].valid) 870 continue; 871 if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_remaining ( 872 keys[i].start_time.abs_time), 873 >, 874 GNUNET_TIME_UNIT_SECONDS)) 875 continue; 876 if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_duration ( 877 keys[i].start_time.abs_time), 878 >, 879 keys[i].validity_duration)) 880 continue; 881 { 882 struct TALER_CoinPubHashP c_hash; 883 struct TALER_PlanchetDetail pd; 884 union GNUNET_CRYPTO_BlindSessionNonce nonce; 885 struct TALER_CRYPTO_CsDeriveRequest cdr = { 886 .h_cs = &keys[i].h_cs, 887 .nonce = &nonce.cs_nonce 888 }; 889 890 TALER_cs_withdraw_nonce_derive ( 891 &ps, 892 &nonce.cs_nonce); 893 ec = TALER_CRYPTO_helper_cs_r_batch_derive ( 894 dh, 895 1, 896 &cdr, 897 true, 898 &bv.details.cs_values); 899 if (TALER_EC_NONE != ec) 900 continue; 901 TALER_planchet_setup_coin_priv (&ps, 902 &alg_values, 903 &coin_priv); 904 TALER_planchet_blinding_secret_create (&ps, 905 &alg_values, 906 &bks); 907 GNUNET_assert (GNUNET_YES == 908 TALER_planchet_prepare (&keys[i].denom_pub, 909 &alg_values, 910 &bks, 911 &nonce, 912 &coin_priv, 913 NULL, /* no age commitment */ 914 &c_hash, 915 &pd)); 916 /* use this key as long as it works */ 917 while (1) 918 { 919 struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get (); 920 struct GNUNET_TIME_Relative delay; 921 struct TALER_CRYPTO_CsSignRequest csr; 922 923 csr.h_cs = &keys[i].h_cs; 924 csr.blinded_planchet 925 = &pd.blinded_planchet.blinded_message->details.cs_blinded_message; 926 ec = TALER_CRYPTO_helper_cs_batch_sign ( 927 dh, 928 1, 929 &csr, 930 true, 931 &ds); 932 if (TALER_EC_NONE != ec) 933 break; 934 delay = GNUNET_TIME_absolute_get_duration (start); 935 duration = GNUNET_TIME_relative_add (duration, 936 delay); 937 TALER_blinded_denom_sig_free (&ds); 938 j++; 939 if (NUM_SIGN_PERFS <= j) 940 break; 941 } 942 TALER_blinded_planchet_free (&pd.blinded_planchet); 943 } 944 } /* for i */ 945 } /* for j */ 946 fprintf (stderr, 947 "%u (%s) signature operations took %s\n", 948 (unsigned int) NUM_SIGN_PERFS, 949 type, 950 GNUNET_STRINGS_relative_time_to_string (duration, 951 GNUNET_YES)); 952 return 0; 953 } 954 955 956 /** 957 * Parallel signing logic. 958 * 959 * @param esh handle to the helper 960 * @return 0 on success 961 */ 962 static int 963 par_signing (struct GNUNET_CONFIGURATION_Handle *cfg) 964 { 965 struct GNUNET_TIME_Absolute start; 966 struct GNUNET_TIME_Relative duration; 967 pid_t pids[NUM_CORES]; 968 struct TALER_CRYPTO_CsDenominationHelper *dh; 969 970 start = GNUNET_TIME_absolute_get (); 971 for (unsigned int i = 0; i<NUM_CORES; i++) 972 { 973 pids[i] = fork (); 974 num_keys = 0; 975 GNUNET_assert (-1 != pids[i]); 976 if (0 == pids[i]) 977 { 978 int ret; 979 980 dh = TALER_CRYPTO_helper_cs_connect (cfg, 981 "taler-exchange", 982 &key_cb, 983 NULL); 984 GNUNET_assert (NULL != dh); 985 ret = perf_signing (dh, 986 "parallel"); 987 TALER_CRYPTO_helper_cs_disconnect (dh); 988 free_keys (); 989 exit (ret); 990 } 991 } 992 for (unsigned int i = 0; i<NUM_CORES; i++) 993 { 994 int wstatus; 995 996 GNUNET_assert (pids[i] == 997 waitpid (pids[i], 998 &wstatus, 999 0)); 1000 } 1001 duration = GNUNET_TIME_absolute_get_duration (start); 1002 fprintf (stderr, 1003 "%u (parallel) signature operations took %s (total real time)\n", 1004 (unsigned int) NUM_SIGN_PERFS * NUM_CORES, 1005 GNUNET_STRINGS_relative_time_to_string (duration, 1006 GNUNET_YES)); 1007 return 0; 1008 } 1009 1010 1011 /** 1012 * Main entry point into the test logic with the helper already running. 1013 */ 1014 static int 1015 run_test (void) 1016 { 1017 struct GNUNET_CONFIGURATION_Handle *cfg; 1018 struct TALER_CRYPTO_CsDenominationHelper *dh; 1019 struct timespec req = { 1020 .tv_nsec = 250000000 1021 }; 1022 int ret; 1023 1024 cfg = GNUNET_CONFIGURATION_create (TALER_EXCHANGE_project_data ()); 1025 if (GNUNET_OK != 1026 GNUNET_CONFIGURATION_load (cfg, 1027 "test_helper_cs.conf")) 1028 { 1029 GNUNET_break (0); 1030 return 77; 1031 } 1032 1033 fprintf (stderr, "Waiting for helper to start ... "); 1034 for (unsigned int i = 0; i<100; i++) 1035 { 1036 nanosleep (&req, 1037 NULL); 1038 dh = TALER_CRYPTO_helper_cs_connect (cfg, 1039 "taler-exchange", 1040 &key_cb, 1041 NULL); 1042 if (NULL != dh) 1043 break; 1044 fprintf (stderr, "."); 1045 } 1046 if (NULL == dh) 1047 { 1048 fprintf (stderr, 1049 "\nFAILED: timeout trying to connect to helper\n"); 1050 GNUNET_CONFIGURATION_destroy (cfg); 1051 return 1; 1052 } 1053 if (0 == num_keys) 1054 { 1055 fprintf (stderr, 1056 "\nFAILED: timeout trying to connect to helper\n"); 1057 TALER_CRYPTO_helper_cs_disconnect (dh); 1058 GNUNET_CONFIGURATION_destroy (cfg); 1059 return 1; 1060 } 1061 fprintf (stderr, 1062 " Done (%u keys)\n", 1063 num_keys); 1064 ret = 0; 1065 if (0 == ret) 1066 ret = test_revocation (dh); 1067 if (0 == ret) 1068 ret = test_r_derive (dh); 1069 if (0 == ret) 1070 ret = test_signing (dh); 1071 if (0 == ret) 1072 ret = test_batch_signing (dh, 1073 2, 1074 true); 1075 if (0 == ret) 1076 ret = test_batch_signing (dh, 1077 64, 1078 true); 1079 for (unsigned int i = 0; i<4; i++) 1080 { 1081 static unsigned int batches[] = { 1, 4, 16, 64 }; 1082 unsigned int batch_size = batches[i]; 1083 struct GNUNET_TIME_Absolute start; 1084 struct GNUNET_TIME_Relative duration; 1085 1086 start = GNUNET_TIME_absolute_get (); 1087 if (0 != ret) 1088 break; 1089 ret = test_batch_signing (dh, 1090 batch_size, 1091 false); 1092 duration = GNUNET_TIME_absolute_get_duration (start); 1093 fprintf (stderr, 1094 "%4u (batch) signature operations took %s (total real time)\n", 1095 (unsigned int) batch_size, 1096 GNUNET_STRINGS_relative_time_to_string (duration, 1097 GNUNET_YES)); 1098 } 1099 if (0 == ret) 1100 ret = perf_signing (dh, 1101 "sequential"); 1102 TALER_CRYPTO_helper_cs_disconnect (dh); 1103 free_keys (); 1104 if (0 == ret) 1105 ret = par_signing (cfg); 1106 /* clean up our state */ 1107 GNUNET_CONFIGURATION_destroy (cfg); 1108 return ret; 1109 } 1110 1111 1112 int 1113 main (int argc, 1114 const char *const argv[]) 1115 { 1116 struct GNUNET_Process *helper; 1117 char *libexec_dir; 1118 char *binary_name; 1119 int ret; 1120 enum GNUNET_OS_ProcessStatusType type; 1121 unsigned long code; 1122 const char *loglev = "WARNING"; 1123 1124 (void) argc; 1125 (void) argv; 1126 unsetenv ("XDG_DATA_HOME"); 1127 unsetenv ("XDG_CONFIG_HOME"); 1128 GNUNET_log_setup ("test-helper-cs", 1129 loglev, 1130 NULL); 1131 libexec_dir = GNUNET_OS_installation_get_path (TALER_EXCHANGE_project_data (), 1132 GNUNET_OS_IPK_BINDIR); 1133 GNUNET_asprintf (&binary_name, 1134 "%s/%s", 1135 libexec_dir, 1136 "taler-exchange-secmod-cs"); 1137 GNUNET_free (libexec_dir); 1138 helper = GNUNET_process_create (GNUNET_OS_INHERIT_STD_ERR); 1139 if (GNUNET_OK != 1140 GNUNET_process_run_command_va (helper, 1141 binary_name, 1142 binary_name, 1143 "-c", 1144 "test_helper_cs.conf", 1145 "-L", 1146 loglev, 1147 NULL)) 1148 { 1149 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, 1150 "exec", 1151 binary_name); 1152 GNUNET_process_destroy (helper); 1153 GNUNET_free (binary_name); 1154 return 77; 1155 } 1156 GNUNET_free (binary_name); 1157 ret = run_test (); 1158 1159 GNUNET_break (GNUNET_OK == 1160 GNUNET_process_kill (helper, 1161 SIGTERM)); 1162 if (GNUNET_OK != 1163 GNUNET_process_wait (helper, 1164 true, 1165 &type, 1166 &code)) 1167 { 1168 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1169 "Helper process did not die voluntarily, killing hard\n"); 1170 GNUNET_break (GNUNET_OK == 1171 GNUNET_process_kill (helper, 1172 SIGKILL)); 1173 ret = 4; 1174 } 1175 else if ( (GNUNET_OS_PROCESS_EXITED != type) || 1176 (0 != code) ) 1177 { 1178 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1179 "Helper died with unexpected status %d/%d\n", 1180 (int) type, 1181 (int) code); 1182 ret = 5; 1183 } 1184 GNUNET_process_destroy (helper); 1185 return ret; 1186 } 1187 1188 1189 /* end of test_helper_cs.c */