frosix_api_keygen.c (40002B)
1 /* 2 This file is part of Frosix 3 Copyright (C) 2020, 2021 Anastasis SARL 4 5 Frosix 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 Frosix 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 Frosix; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file reducer/frosix_api_keygen.c 18 * @brief frosix reducer keygen api 19 * @author Christian Grothoff 20 * @author Dominik Meister 21 * @author Dennis Neufeld 22 * @author Joel Urech 23 */ 24 25 #include "platform.h" 26 #include "frosix.h" 27 #include "frosix_api.h" 28 #include <taler/taler_merchant_service.h> 29 #include <time.h> 30 31 #define FROSIX_KDF_CONTEXT "FROSIX-KEY" 32 33 /** 34 * FIXME 35 */ 36 struct FROSIX_DkgProvider 37 { 38 /** 39 * Name of the provider 40 */ 41 char *provider_name; 42 43 /** 44 * URL of the provider. 45 */ 46 char *backend_url; 47 48 /** 49 * Public provider salt 50 */ 51 struct FROSIX_ProviderSaltP provider_salt; 52 53 /** 54 * Long term public key of the provider 55 */ 56 struct GNUNET_CRYPTO_EddsaPublicKey provider_public_key; 57 58 /** 59 * Index of the provider 60 */ 61 uint8_t provider_index; 62 63 /** 64 * Authentication method. 65 */ 66 char *auth_method; 67 68 /** 69 * Authentication data. 70 */ 71 char *auth_data; 72 73 /** 74 * Answer to the question in @e auth_data. 75 * This field is optional and only used if authentication method is of type 76 * security question. 77 */ 78 char *auth_answer; 79 80 /** 81 * Context String for this provider. 82 */ 83 struct FROSIX_DkgContextStringP context_string; 84 85 /** 86 * Salt for the hash of the authentication data 87 */ 88 struct GNUNET_HashCode hash_salt; 89 90 /** 91 * Salted hash of the challenge data 92 */ 93 struct FROSIX_ChallengeHashP auth_hash; 94 95 /** 96 * Commitments which we get from round 1 97 */ 98 struct FROSIX_DkgCommitment commitment; 99 100 /** 101 * Pre encryption key 102 */ 103 struct FROSIX_EncryptionKey pre_enc_key; 104 105 /** 106 * All the secret shares received from this provider. 107 * Number or length of this array is always `number_of_participants - 1` 108 */ 109 struct FROSIX_DkgSecretShare *secret_shares; 110 111 /** 112 * Public key, should be the same at all providers 113 */ 114 struct FROST_PublicKey public_key; 115 116 /** 117 * Provider's signature over public key and authentication data. 118 */ 119 struct GNUNET_CRYPTO_EddsaSignature providers_signature; 120 121 /** 122 * Seed of provider 123 */ 124 uint8_t seed[64]; 125 }; 126 127 128 /** 129 * Struct to store all parsed data from the cli and /config and /seed 130 */ 131 struct FROSIX_DkgData 132 { 133 /** 134 * What is the threshold value? 135 */ 136 uint8_t threshold; 137 138 /** 139 * Number of participating providers. Is the length of the @e providers array 140 */ 141 uint8_t num_of_participants; 142 143 /** 144 * Our master key we have to export at the end of the DKG. 145 */ 146 struct GNUNET_HashCode master_key; 147 148 /** 149 * Pointer to a list of providers 150 */ 151 struct FROSIX_DkgProvider *providers; 152 153 /** 154 * Array of the public keys from all providers. 155 * Length is @e num_of_participants 156 */ 157 struct GNUNET_CRYPTO_EddsaPublicKey *providers_public_keys; 158 159 /** 160 * Number of years the key data should be stored at the providers. 161 */ 162 uint64_t expiration; 163 }; 164 165 166 /** 167 * State of a keygen procedure 168 */ 169 struct FROSIX_DkgState 170 { 171 /** 172 * State we are updating. 173 */ 174 struct FROSIX_DkgData *dkg_data; 175 176 /** 177 * Function to call when we are done. 178 */ 179 FROSIX_ActionCallback cb; 180 181 /** 182 * Closure for @e cb. 183 */ 184 void *cb_cls; 185 186 /** 187 * Redux action we returned to our controller. 188 */ 189 struct FROSIX_ReduxAction ra; 190 191 /** 192 * Number of provider operations that are still awaiting completion. 193 */ 194 uint8_t counter; 195 196 /** 197 * Last error code 198 */ 199 enum TALER_ErrorCode error_code; 200 201 /** 202 * Array of config requests, with length `num_of_participants` 203 */ 204 struct FROSIX_ConfigOperation **co; 205 206 /** 207 * Array of seed requests, with length `num_of_participants` 208 */ 209 struct FROSIX_SeedGetOperation **sgo; 210 211 /** 212 * DKG-Commitment Requests 213 */ 214 struct FROSIX_DkgCommitmentRequestOperation **dco; 215 216 /** 217 * DKG-Share Requests 218 */ 219 struct FROSIX_DkgShareRequestOperation **dso; 220 221 /** 222 * DKG-Key Requests 223 */ 224 struct FROSIX_DkgKeyStoreOperation **dko; 225 }; 226 227 228 /** 229 * Helper function to free all initialized memory of a 230 * `struct FROSIX_DkgProvider` 231 * 232 * @param dp Pointer to the provider we want to free the memory. 233 */ 234 static void 235 free_dkg_provider_struct (struct FROSIX_DkgProvider *dp) 236 { 237 if (NULL != dp->provider_name) 238 GNUNET_free (dp->provider_name); 239 240 if (NULL != dp->backend_url) 241 GNUNET_free (dp->backend_url); 242 243 if (NULL != dp->auth_method) 244 GNUNET_free (dp->auth_method); 245 246 if (NULL != dp->auth_data) 247 GNUNET_free (dp->auth_data); 248 249 if (NULL != dp->auth_answer) 250 GNUNET_free (dp->auth_answer); 251 252 FROST_free_dkg_commitment (&dp->commitment.commitment, 253 1); 254 255 if (NULL != dp->secret_shares) 256 GNUNET_free (dp->secret_shares); 257 } 258 259 260 /** 261 * Function to free all initialized memory of a provider from a 262 * `struct FROSIX_DkgData` 263 * 264 * @param dd the struct to clean up 265 */ 266 static void 267 free_dkg_data_struct (struct FROSIX_DkgData *dd) 268 { 269 /* go through all providers - if any */ 270 if (NULL != dd->providers) 271 { 272 for (unsigned int i = 0; i < dd->num_of_participants; i++) 273 { 274 if (NULL != &dd->providers[i]) 275 free_dkg_provider_struct (&dd->providers[i]); 276 } 277 GNUNET_free (dd->providers); 278 } 279 280 if (NULL != dd->providers_public_keys) 281 GNUNET_free (dd->providers_public_keys); 282 } 283 284 285 /** 286 * Function called when keygen is being aborted. 287 * Frees all initialized memory! 288 * 289 * @param cls a `struct FROSIX_DkgState` 290 */ 291 static void 292 keygen_cancel_cb (void *cls) 293 { 294 struct FROSIX_DkgState *ds = cls; 295 296 /* free dkg data */ 297 if (NULL != ds->dkg_data) 298 { 299 free_dkg_data_struct (ds->dkg_data); 300 GNUNET_free (ds->dkg_data); 301 } 302 303 /* free operations */ 304 if (NULL != ds->co) 305 GNUNET_free (ds->co); 306 307 if (NULL != ds->sgo) 308 GNUNET_free (ds->sgo); 309 310 if (NULL != ds->dco) 311 GNUNET_free (ds->dco); 312 313 if (NULL != ds->dso) 314 GNUNET_free (ds->dso); 315 316 if (NULL != ds->dko) 317 GNUNET_free (ds->dko); 318 319 /* free dkg state */ 320 GNUNET_free (ds); 321 } 322 323 324 /** 325 * FIXME: move to frosix common crypto functions library! 326 */ 327 static void 328 derive_encryption_key ( 329 struct FROSIX_EncryptionKey *enc_key, 330 const struct FROSIX_EncryptionKey *pre_enc_key, 331 const struct FROST_PublicKey *pk, 332 const struct FROSIX_ProviderSaltP *provider_salt, 333 uint8_t provider_index) 334 { 335 GNUNET_CRYPTO_kdf (enc_key, 336 sizeof (*enc_key), 337 FROSIX_KDF_CONTEXT, 338 sizeof (FROSIX_KDF_CONTEXT), 339 pre_enc_key, 340 sizeof (*pre_enc_key), 341 pk, 342 sizeof (*pk), 343 provider_salt, 344 sizeof (*provider_salt), 345 &provider_index, 346 sizeof (provider_index), 347 NULL, 348 0); 349 } 350 351 /** 352 * Helper function to build an array out of all provider public keys. 353 * The assembled array is then stored in our @a dd struct. 354 * 355 * @param dd Our main struct to store all relevant data in. 356 */ 357 static void 358 keygen_build_public_key_array (struct FROSIX_DkgData *dd) 359 { 360 /* prepare array of providers public keys */ 361 dd->providers_public_keys = GNUNET_malloc ( 362 dd->num_of_participants 363 * sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); 364 365 GNUNET_assert (NULL != dd->providers_public_keys); 366 367 for (unsigned int i = 0; i < dd->num_of_participants; i++) 368 { 369 memcpy (&dd->providers_public_keys[i], 370 &dd->providers[i].provider_public_key, 371 sizeof (dd->providers->provider_public_key)); 372 } 373 } 374 375 376 /** 377 * This function gets called after we have received a positive result from all 378 * providers. It prepares a json struct, which we then return back to the cli. 379 * 380 * @param ds The state of our keygen process. 381 */ 382 static void 383 keygen_prepare_result (struct FROSIX_DkgState *ds) 384 { 385 /* first check if signature from providers can be verified. */ 386 // FIXME: define constant for size of ps struct 387 for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) 388 { 389 struct FROSIX_DkgProvider *dp = &ds->dkg_data->providers[i]; 390 391 struct FROSIX_DkgKeySignaturePS ks = { 392 .purpose.purpose = htonl (104), 393 .purpose.size = htonl (sizeof (ks)), 394 .public_key = dp->public_key, 395 .auth_hash = dp->auth_hash, 396 }; 397 398 GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_verify ( 399 104, 400 &ks, 401 &dp->providers_signature, 402 &dp->provider_public_key)); 403 } 404 405 /* check if every reported public key is the same */ 406 for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) 407 { 408 if (GNUNET_OK != FROST_point_cmp ( 409 &ds->dkg_data->providers[i].public_key.pk, 410 &ds->dkg_data->providers[0].public_key.pk)) 411 { 412 json_t *error_message; 413 error_message = GNUNET_JSON_PACK ( 414 GNUNET_JSON_pack_string ("Frosix_client_error", 415 "Public keys do not match")); 416 417 ds->cb (ds->cb_cls, 418 0, 419 error_message); 420 421 return; 422 } 423 } 424 425 /* calculate encryption keys */ 426 struct FROSIX_EncryptionKey enc_keys[ds->dkg_data->num_of_participants]; 427 for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) 428 { 429 struct FROSIX_DkgProvider *dp = &ds->dkg_data->providers[i]; 430 derive_encryption_key (&enc_keys[i], 431 &dp->pre_enc_key, 432 &dp->public_key, 433 &dp->provider_salt, 434 dp->provider_index); 435 } 436 437 /* build json */ 438 json_t *result; 439 json_t *providers = json_array (); 440 441 for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) 442 { 443 /* build single provider */ 444 struct FROSIX_DkgProvider *dp = &ds->dkg_data->providers[i]; 445 json_t *provider; 446 provider = GNUNET_JSON_PACK ( 447 GNUNET_JSON_pack_uint64 ("provider_index", 448 dp->provider_index), 449 GNUNET_JSON_pack_string ("provider_name", 450 dp->provider_name), 451 GNUNET_JSON_pack_string ("backend_url", 452 dp->backend_url), 453 GNUNET_JSON_pack_data_auto ("encryption_key", 454 &enc_keys[i]), 455 GNUNET_JSON_pack_string ("auth_method", 456 dp->auth_method), 457 GNUNET_JSON_pack_string ("auth_data", 458 dp->auth_data), 459 GNUNET_JSON_pack_data_auto ("auth_nonce", 460 &dp->hash_salt), 461 GNUNET_JSON_pack_data_auto ("auth_hash", 462 &dp->auth_hash), 463 GNUNET_JSON_pack_data_auto ("provider_signature", 464 &dp->providers_signature), 465 GNUNET_JSON_pack_data_auto ("provider_public_key", 466 &dp->provider_public_key)); 467 468 /* add to provider array */ 469 GNUNET_assert (0 == 470 json_array_append_new ( 471 providers, 472 provider)); 473 } 474 475 result = GNUNET_JSON_PACK ( 476 GNUNET_JSON_pack_data_auto ("public_key", 477 &ds->dkg_data->providers[0].public_key), 478 GNUNET_JSON_pack_uint64 ("number_of_participants", 479 ds->dkg_data->num_of_participants), 480 GNUNET_JSON_pack_uint64 ("threshold", 481 ds->dkg_data->threshold), 482 GNUNET_JSON_pack_array_steal ("providers", 483 providers)); 484 485 /* free all initialized data */ 486 free_dkg_data_struct (ds->dkg_data); 487 488 ds->cb (ds->cb_cls, 489 ds->error_code, 490 result); 491 } 492 493 494 /** 495 * Callback to process a POST /dkg-key request 496 * 497 * @param cls closure 498 * @param dcd the decoded response body 499 */ 500 static void 501 dkg_key_request_cb (void *cls, 502 const struct FROSIX_DkgKeyStoreDetails *dkd) 503 { 504 GNUNET_assert (NULL != cls); 505 struct FROSIX_DkgState *ds = cls; 506 507 if (0 >= ds->counter) 508 { 509 /* We haven't expected this callback, thus just ignore it */ 510 return; 511 } 512 513 /* check if the call was successful */ 514 if (0 == dkd->http_status) 515 { 516 ds->counter = 0; 517 518 // FIXME: cancel all other running and not yet returned requests 519 json_t *error_message; 520 error_message = GNUNET_JSON_PACK ( 521 GNUNET_JSON_pack_string ("Frosix_client_error", 522 "Error requesting dkg key from provider")); 523 524 ds->cb (ds->cb_cls, 525 0, 526 error_message); 527 528 return; 529 } 530 531 /* set error code */ 532 ds->error_code = dkd->ec; 533 534 /* check if provider index is valid */ 535 GNUNET_assert (0 < dkd->provider_index); 536 GNUNET_assert (ds->dkg_data->num_of_participants >= dkd->provider_index); 537 538 /* copy commitment in our struct - just assign pointer */ 539 struct FROSIX_DkgProvider *dp = &ds->dkg_data->providers[dkd->provider_index 540 - 1]; 541 542 memcpy (&dp->public_key, 543 &dkd->details.public_key, 544 sizeof (dkd->details.public_key)); 545 546 memcpy (&dp->providers_signature, 547 &dkd->details.signature, 548 sizeof (dkd->details.signature)); 549 550 /* call next dkg-commitment request */ 551 ds->counter--; 552 if (0 == ds->counter) 553 { 554 /* we are the last, go ahead with checking our result */ 555 GNUNET_free (ds->dko); 556 ds->dko = NULL; 557 keygen_prepare_result (ds); 558 } 559 } 560 561 562 /** 563 * FIXME 564 */ 565 static void 566 start_dkg_key (struct FROSIX_DkgState *ds) 567 { 568 ds->dko = GNUNET_malloc (ds->dkg_data->num_of_participants * sizeof (char *)); 569 ds->counter = 0; 570 571 for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) 572 { 573 struct FROSIX_DkgData *dd = ds->dkg_data; 574 struct FROSIX_DkgProvider *dp = &ds->dkg_data->providers[i]; 575 576 /* set up array of secret shares */ 577 struct FROSIX_DkgKeyStoreShare secret_shares[dd->num_of_participants - 1]; 578 579 for (unsigned int j = 0; j < dd->num_of_participants; j++) 580 { 581 if (j < i) 582 { 583 /* check if target of the secret share matches */ 584 if (dp->provider_index != dd->providers[j].secret_shares[i - 1].target) 585 { 586 json_t *error_message; 587 error_message = GNUNET_JSON_PACK ( 588 GNUNET_JSON_pack_string ("Frosix_client_error", 589 "Error while assigning the secret shares")); 590 591 ds->cb (ds->cb_cls, 592 0, 593 error_message); 594 595 return; 596 } 597 598 secret_shares[j].identifier = 599 dd->providers[j].secret_shares[i - 1].issuer; 600 601 memcpy (&secret_shares[j].secret_share, 602 &dd->providers[j].secret_shares[i - 1].encrypted_share, 603 sizeof (dd->providers[j].secret_shares[i - 1].encrypted_share)); 604 memcpy (&secret_shares[j].ephemeral_key, 605 &dd->providers[j].secret_shares[i - 1].ephemeral_key, 606 sizeof (dd->providers[j].secret_shares[i - 1].ephemeral_key)); 607 } 608 else if (j > i) 609 { 610 /* check if target of the secret share matches */ 611 if (dp->provider_index != dd->providers[j].secret_shares[i].target) 612 { 613 json_t *error_message; 614 error_message = GNUNET_JSON_PACK ( 615 GNUNET_JSON_pack_string ("Frosix_client_error", 616 "Error while assigning the secret shares")); 617 618 ds->cb (ds->cb_cls, 619 0, 620 error_message); 621 622 return; 623 } 624 625 secret_shares[j - 1].identifier = 626 dd->providers[j].secret_shares[i].issuer; 627 memcpy (&secret_shares[j - 1].secret_share, 628 &dd->providers[j].secret_shares[i].encrypted_share, 629 sizeof (dd->providers[j].secret_shares[i].encrypted_share)); 630 memcpy (&secret_shares[j - 1].ephemeral_key, 631 &dd->providers[j].secret_shares[i].ephemeral_key, 632 sizeof (dd->providers[j].secret_shares[i].ephemeral_key)); 633 } 634 } 635 636 /* compute request id */ 637 struct FROSIX_DkgRequestIdP request_id; 638 FROSIX_compute_dkg_request_id ( 639 &request_id, 640 &dp->context_string, 641 &dp->auth_hash, 642 &dp->provider_salt, 643 dp->provider_index, 644 ds->dkg_data->num_of_participants, 645 ds->dkg_data->threshold); 646 647 ds->dko[i] = FROSIX_dkg_key_store ( 648 FROSIX_REDUX_ctx_, 649 dp->backend_url, 650 &request_id, 651 dp->provider_index, 652 dd->threshold, 653 dd->num_of_participants, 654 &dp->context_string, 655 &dp->auth_hash, 656 dd->providers_public_keys, 657 &dp->pre_enc_key, 658 dd->expiration, 659 secret_shares, 660 dd->num_of_participants - 1, 661 &dkg_key_request_cb, 662 ds); 663 664 ds->counter++; 665 } 666 } 667 668 669 /** 670 * Callback to process a POST /dkg-shares request 671 * 672 * @param cls closure 673 * @param dcd the decoded response body 674 */ 675 static void 676 dkg_share_request_cb (void *cls, 677 const struct FROSIX_DkgShareRequestDetails *dsd) 678 { 679 GNUNET_assert (NULL != cls); 680 struct FROSIX_DkgState *ds = cls; 681 682 if (0 >= ds->counter) 683 { 684 /* We haven't expected this callback, thus just ignore it */ 685 return; 686 } 687 688 /* check if the call was successful */ 689 if (0 == dsd->http_status) 690 { 691 ds->counter = 0; 692 693 // FIXME: cancel all other running and not yet returned requests 694 json_t *error_message; 695 error_message = GNUNET_JSON_PACK ( 696 GNUNET_JSON_pack_string ("Frosix_client_error", 697 "Error requesting dkg shares from provider")); 698 699 ds->cb (ds->cb_cls, 700 0, 701 error_message); 702 703 return; 704 } 705 706 /* set error code */ 707 ds->error_code = dsd->ec; 708 709 /* check if provider index is valid */ 710 GNUNET_assert (0 < dsd->provider_index); 711 GNUNET_assert (ds->dkg_data->num_of_participants >= dsd->provider_index); 712 713 /* check number of secret shares */ 714 if (ds->dkg_data->num_of_participants - 1 != dsd->shares_len) 715 { 716 ds->counter = 0; 717 718 // FIXME: cancel all other running and not yet returned requests 719 json_t *error_message; 720 error_message = GNUNET_JSON_PACK ( 721 GNUNET_JSON_pack_string ("Frosix_client_error", 722 "Error in dkg shares response")); 723 724 ds->cb (ds->cb_cls, 725 0, 726 error_message); 727 728 return; 729 } 730 731 /* check if our provider index is same as in the response */ 732 for (unsigned int i = 0; i < dsd->shares_len; i++) 733 { 734 if (dsd->provider_index != dsd->shares[i].issuer) 735 { 736 ds->counter = 0; 737 738 // FIXME: cancel all other running and not yet returned requests 739 json_t *error_message; 740 error_message = GNUNET_JSON_PACK ( 741 GNUNET_JSON_pack_string ("Frosix_client_error", 742 "Error in dkg shares response")); 743 744 ds->cb (ds->cb_cls, 745 0, 746 error_message); 747 748 return; 749 } 750 } 751 752 /* copy commitment in our struct - just assign pointer */ 753 ds->dkg_data->providers[dsd->provider_index - 1].secret_shares = dsd->shares; 754 755 /* call next dkg-commitment request */ 756 ds->counter--; 757 if (0 == ds->counter) 758 { 759 /* we are the last, go ahead with dkg-key */ 760 GNUNET_free (ds->dso); 761 ds->dso = NULL; 762 start_dkg_key (ds); 763 } 764 } 765 766 767 /** 768 * FIXME 769 */ 770 static void 771 start_dkg_shares (struct FROSIX_DkgState *ds) 772 { 773 ds->dso = GNUNET_malloc (ds->dkg_data->num_of_participants * sizeof (char *)); 774 ds->counter = 0; 775 776 for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) 777 { 778 struct FROSIX_DkgData *dd = ds->dkg_data; 779 struct FROSIX_DkgProvider *dp = &ds->dkg_data->providers[i]; 780 781 /* set up array of dkg commitments */ 782 struct FROSIX_DkgCommitment dkg_commitments[dd->num_of_participants - 1]; 783 for (unsigned int j = 0; j < dd->num_of_participants; j++) 784 { 785 if (j < i) 786 { 787 dkg_commitments[j] = dd->providers[j].commitment; 788 } 789 else if (j > i) 790 { 791 dkg_commitments[j - 1] = dd->providers[j].commitment; 792 } 793 } 794 795 /* compute request id */ 796 struct FROSIX_DkgRequestIdP request_id; 797 FROSIX_compute_dkg_request_id ( 798 &request_id, 799 &dp->context_string, 800 &dp->auth_hash, 801 &dp->provider_salt, 802 dp->provider_index, 803 ds->dkg_data->num_of_participants, 804 ds->dkg_data->threshold); 805 806 ds->dso[i] = FROSIX_dkg_share_request ( 807 FROSIX_REDUX_ctx_, 808 dp->backend_url, 809 &request_id, 810 dp->provider_index, 811 dd->threshold, 812 dd->num_of_participants, 813 &dp->context_string, 814 &dp->auth_hash, 815 dkg_commitments, 816 dd->num_of_participants - 1, 817 dd->providers_public_keys, 818 &dkg_share_request_cb, 819 ds); 820 821 ds->counter++; 822 } 823 824 /* free dkg commitments */ 825 for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) 826 { 827 FROST_free_dkg_commitment ( 828 &ds->dkg_data->providers[i].commitment.commitment, 829 1); 830 } 831 } 832 833 834 /** 835 * Callback to process a POST /dkg-commitment request 836 * 837 * @param cls closure 838 * @param dcd the decoded response body 839 */ 840 static void 841 dkg_commitment_request_cb (void *cls, 842 const struct FROSIX_DkgCommitmentRequestDetails *dcd) 843 { 844 GNUNET_assert (NULL != cls); 845 struct FROSIX_DkgState *ds = cls; 846 847 if (0 >= ds->counter) 848 { 849 /* We haven't expected this callback, thus just ignore it */ 850 return; 851 } 852 853 /* check if the call was successful */ 854 if (0 == dcd->http_status) 855 { 856 ds->counter = 0; 857 858 // FIXME: cancel all other running and not yet returned requests 859 json_t *error_message; 860 error_message = GNUNET_JSON_PACK ( 861 GNUNET_JSON_pack_string ("Frosix_client_error", 862 "Error requesting dkg commitment from provider")); 863 864 ds->cb (ds->cb_cls, 865 0, 866 error_message); 867 868 return; 869 } 870 871 /* set error code */ 872 ds->error_code = dcd->ec; 873 874 /* check if provider index is valid */ 875 GNUNET_assert (0 < dcd->provider_index); 876 GNUNET_assert (ds->dkg_data->num_of_participants >= dcd->provider_index); 877 878 /* check if our provider index is same as in the response */ 879 if (dcd->provider_index != dcd->dkg_commitment.identifier) 880 { 881 ds->counter--; 882 883 // FIXME: cancel all other running and not yet returned requests 884 json_t *error_message; 885 error_message = GNUNET_JSON_PACK ( 886 GNUNET_JSON_pack_string ("Frosix_client_error", 887 "Error in dkg commitment response")); 888 889 ds->cb (ds->cb_cls, 890 0, 891 error_message); 892 893 return; 894 } 895 896 /* check if length of commitments equals our threshold value */ 897 if (dcd->dkg_commitment.shares_commitments_length != ds->dkg_data->threshold) 898 { 899 ds->counter = 0; 900 901 // FIXME: cancel all other running and not yet returned requests 902 json_t *error_message; 903 error_message = GNUNET_JSON_PACK ( 904 GNUNET_JSON_pack_string ("Frosix_client_error", 905 "Error in dkg commitment response")); 906 907 ds->cb (ds->cb_cls, 908 0, 909 error_message); 910 911 return; 912 } 913 914 /* copy commitment in our struct */ 915 struct FROSIX_DkgProvider *dp = &ds->dkg_data->providers[dcd->provider_index 916 - 1]; 917 918 /* Fill return values in our central struct */ 919 memcpy (&dp->commitment.encryption_public_key, 920 &dcd->public_key, 921 sizeof (dcd->public_key)); 922 923 FROST_initialize_dkg_commitment ( 924 &dp->commitment.commitment, 925 dcd->provider_index, 926 dcd->dkg_commitment.shares_commitments_length); 927 928 for (unsigned int i = 0; i < dcd->dkg_commitment.shares_commitments_length; 929 i++) 930 { 931 memcpy (&dp->commitment.commitment.share_comm[i], 932 &dcd->dkg_commitment.share_comm[i], 933 sizeof (dcd->dkg_commitment.share_comm[i])); 934 } 935 936 memcpy (&dp->commitment.commitment.zkp.r, 937 &dcd->dkg_commitment.zkp.r, 938 sizeof (dcd->dkg_commitment.zkp.r)); 939 940 memcpy (&dp->commitment.commitment.zkp.z, 941 &dcd->dkg_commitment.zkp.z, 942 sizeof (dcd->dkg_commitment.zkp.z)); 943 944 /* call next dkg-commitment request */ 945 ds->counter--; 946 if (0 == ds->counter) 947 { 948 /* we are the last, go ahead with dkg-share */ 949 GNUNET_free (ds->dco); 950 ds->dco = NULL; 951 start_dkg_shares (ds); 952 } 953 } 954 955 956 /** 957 * Function to derive the master key and all context strings. 958 * 959 * @param[in,out] dd the struct to fill in the entropy 960 * @param[in] client_entropy high entropy bytes to derive more high entropy bytes 961 */ 962 static void 963 keygen_derive_entropy (struct FROSIX_DkgData *dd, 964 const struct GNUNET_HashCode *client_entropy, 965 const struct GNUNET_HashCode *provider_entropy) 966 { 967 { 968 /* derive high entropy bytes */ 969 size_t length = sizeof (dd->master_key) 970 + (dd->num_of_participants 971 * sizeof (dd->providers->context_string)); 972 973 char *derived_entropy = GNUNET_malloc (length); 974 975 /* kill process if allocation failed */ 976 GNUNET_assert (NULL != derived_entropy); 977 978 GNUNET_assert (GNUNET_CRYPTO_kdf (derived_entropy, 979 length, 980 "FROSIX", 981 strlen ("FROSIX"), 982 client_entropy, 983 sizeof (*client_entropy), 984 provider_entropy, 985 sizeof (*provider_entropy), 986 NULL, 987 0)); 988 989 /* copy the derived bytes to the right place */ 990 unsigned int byte_counter = 0; 991 memcpy (&dd->master_key, 992 &derived_entropy[byte_counter], 993 sizeof (dd->master_key)); 994 byte_counter += sizeof (dd->master_key); 995 996 for (unsigned int i = 0; i < dd->num_of_participants; i++) 997 { 998 memcpy (&dd->providers[i].context_string, 999 &derived_entropy[byte_counter], 1000 sizeof (dd->providers->context_string)); 1001 byte_counter += sizeof (dd->providers->context_string); 1002 } 1003 1004 /* free allocated memory */ 1005 GNUNET_free (derived_entropy); 1006 } 1007 1008 { 1009 /* derive authentication salts and pre encryption keys */ 1010 size_t length = dd->num_of_participants 1011 * (sizeof (dd->providers->hash_salt) 1012 + sizeof (dd->providers->pre_enc_key)); 1013 1014 char *client_entropy = GNUNET_malloc (length); 1015 1016 /* kill process if allocation failed */ 1017 GNUNET_assert (NULL != client_entropy); 1018 1019 GNUNET_CRYPTO_kdf (client_entropy, 1020 length, 1021 "FROSIX", 1022 strlen ("FROSIX"), 1023 &dd->master_key, 1024 sizeof (dd->master_key), 1025 NULL, 1026 0); 1027 1028 /* copy bytes to the right place */ 1029 unsigned int byte_counter = 0; 1030 for (unsigned int i = 0; i < dd->num_of_participants; i++) 1031 { 1032 memcpy (&dd->providers[i].hash_salt, 1033 &client_entropy[byte_counter], 1034 sizeof (dd->providers->hash_salt)); 1035 byte_counter += sizeof (dd->providers->hash_salt); 1036 } 1037 1038 for (unsigned int i = 0; i < dd->num_of_participants; i++) 1039 { 1040 memcpy (&dd->providers[i].pre_enc_key, 1041 &client_entropy[byte_counter], 1042 sizeof (dd->providers->pre_enc_key)); 1043 byte_counter += sizeof (dd->providers->pre_enc_key); 1044 } 1045 1046 /* free allocated memory */ 1047 GNUNET_free (client_entropy); 1048 } 1049 } 1050 1051 1052 /** 1053 * FIXME 1054 */ 1055 static void 1056 merge_provider_entropy (struct GNUNET_HashCode *provider_entropy, 1057 const struct FROSIX_DkgState *ds) 1058 { 1059 struct GNUNET_HashContext *hc = GNUNET_CRYPTO_hash_context_start (); 1060 for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) 1061 { 1062 GNUNET_CRYPTO_hash_context_read (hc, 1063 ds->dkg_data->providers[i].seed, 1064 sizeof (ds->dkg_data->providers[i].seed)); 1065 } 1066 1067 GNUNET_CRYPTO_hash_context_finish (hc, 1068 provider_entropy); 1069 } 1070 1071 1072 /** 1073 * FIXME 1074 */ 1075 static void 1076 start_dkg_commitments (struct FROSIX_DkgState *ds) 1077 { 1078 /* measure cpu speed */ 1079 // unsigned int target_difficulty = 5000; // FIXME 1080 unsigned int amplifier = 1; 1081 { 1082 struct FROST_PowSalt salt; 1083 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, 1084 &salt, 1085 sizeof (salt)); 1086 1087 /* start */ 1088 // clock_t start = clock (); 1089 struct FROST_HashCode hash; 1090 FROST_pow_hash (&hash, 1091 "Frosix", 1092 strlen ("Frosix"), 1093 &salt, 1094 1); 1095 /* end */ 1096 // clock_t end = clock (); 1097 // float seconds = (float) (end - start) / 1000; 1098 // amplifier = target_difficulty / seconds; 1099 1100 } 1101 1102 /* merge provider seeds to a single hash code */ 1103 struct GNUNET_HashCode provider_entropy; 1104 merge_provider_entropy (&provider_entropy, 1105 ds); 1106 1107 /* derive master key, context strings, salts and pre encryption keys */ 1108 struct GNUNET_HashCode client_entropy; 1109 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, 1110 &client_entropy, 1111 sizeof (client_entropy)); 1112 1113 keygen_derive_entropy (ds->dkg_data, 1114 &client_entropy, 1115 &provider_entropy); 1116 1117 /* compute salted hash of authentication data */ 1118 for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) 1119 { 1120 struct FROSIX_DkgProvider *dp = &ds->dkg_data->providers[i]; 1121 if (NULL != dp->auth_answer) 1122 { 1123 /* we have a security question here */ 1124 struct GNUNET_CRYPTO_Edx25519PrivateKey priv; 1125 struct GNUNET_CRYPTO_Edx25519PublicKey pub; 1126 FROSIX_hash_pow (&dp->auth_hash.hash, 1127 &priv, 1128 &pub, 1129 &dp->hash_salt, 1130 dp->auth_answer, 1131 amplifier); 1132 } 1133 else 1134 { 1135 FROSIX_compute_auth_hash (&dp->auth_hash, 1136 dp->auth_data, 1137 &dp->hash_salt); 1138 } 1139 } 1140 1141 ds->dco = GNUNET_malloc (ds->dkg_data->num_of_participants * sizeof (char *)); 1142 ds->counter = 0; 1143 1144 for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) 1145 { 1146 struct FROSIX_DkgProvider *dp = &ds->dkg_data->providers[i]; 1147 1148 /* compute request id */ 1149 struct FROSIX_DkgRequestIdP request_id; 1150 FROSIX_compute_dkg_request_id ( 1151 &request_id, 1152 &dp->context_string, 1153 &dp->auth_hash, 1154 &dp->provider_salt, 1155 dp->provider_index, 1156 ds->dkg_data->num_of_participants, 1157 ds->dkg_data->threshold); 1158 1159 ds->dco[i] = FROSIX_dkg_commitment_request ( 1160 FROSIX_REDUX_ctx_, 1161 dp->backend_url, 1162 &request_id, 1163 dp->provider_index, 1164 ds->dkg_data->threshold, 1165 ds->dkg_data->num_of_participants, 1166 &dp->context_string, 1167 &dp->auth_hash, 1168 ds->dkg_data->providers_public_keys, 1169 &dkg_commitment_request_cb, 1170 ds); 1171 1172 ds->counter++; 1173 } 1174 } 1175 1176 1177 /** 1178 Callback to process a GET /seed request 1179 * 1180 * @param cls closure 1181 * @param ps the decoded response body 1182 */ 1183 static void 1184 seed_request_cb (void *cls, 1185 unsigned int http_status, 1186 const struct FROSIX_ProviderSeed *ps) 1187 { 1188 GNUNET_assert (NULL != cls); 1189 struct FROSIX_DkgState *ds = cls; 1190 1191 if (0 >= ds->counter) 1192 { 1193 /* We haven't expected this callback, thus just ignore it */ 1194 return; 1195 } 1196 1197 /* check if the call was successful */ 1198 if (0 == http_status) 1199 { 1200 ds->counter = 0; 1201 1202 // FIXME: cancel all other running and not yet returned requests 1203 json_t *error_message; 1204 error_message = GNUNET_JSON_PACK ( 1205 GNUNET_JSON_pack_string ("Frosix_client_error", 1206 "Error requesting seed from provider")); 1207 1208 ds->cb (ds->cb_cls, 1209 0, 1210 error_message); 1211 1212 return; 1213 } 1214 1215 /* check if provider index is valid */ 1216 GNUNET_assert (0 < ps->provider_index); 1217 GNUNET_assert (ds->dkg_data->num_of_participants >= ps->provider_index); 1218 1219 /* copy seed to our main struct */ 1220 struct FROSIX_DkgProvider *dp = &ds->dkg_data->providers[ps->provider_index 1221 - 1]; 1222 1223 memcpy (&dp->seed, 1224 ps->seed, 1225 FROSIX_SEED_SIZE); 1226 1227 ds->counter--; 1228 if (0 == ds->counter) 1229 { 1230 GNUNET_free (ds->sgo); 1231 ds->sgo = NULL; 1232 /* we are the last, go ahead with dkg-commitment */ 1233 start_dkg_commitments (ds); 1234 } 1235 } 1236 1237 1238 /** 1239 * FIXME 1240 */ 1241 static void 1242 start_seed_requests (struct FROSIX_DkgState *ds) 1243 { 1244 ds->counter = 0; 1245 ds->sgo = GNUNET_malloc (ds->dkg_data->num_of_participants * sizeof (char *)); 1246 1247 for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) 1248 { 1249 ds->sgo[i] = FROSIX_seed_get (FROSIX_REDUX_ctx_, 1250 ds->dkg_data->providers[i].backend_url, 1251 i + 1, 1252 &seed_request_cb, 1253 ds); 1254 ds->counter++; 1255 } 1256 } 1257 1258 1259 /** 1260 * Callback to process a GET /config request 1261 * 1262 * @param cls closure 1263 * @param fcfg the decoded response body 1264 */ 1265 static void 1266 config_request_cb (void *cls, 1267 unsigned int http_status, 1268 const struct FROSIX_Config *fcfg) 1269 { 1270 GNUNET_assert (NULL != cls); 1271 struct FROSIX_DkgState *ds = cls; 1272 1273 if (0 >= ds->counter) 1274 { 1275 /* We haven't expected this callback, thus just ignore it */ 1276 return; 1277 } 1278 1279 /* check if the call was successful */ 1280 if (0 == http_status) 1281 { 1282 ds->counter = 0; 1283 1284 // FIXME: cancel all other running and not yet returned requests 1285 json_t *error_message; 1286 error_message = GNUNET_JSON_PACK ( 1287 GNUNET_JSON_pack_string ("Frosix_client_error", 1288 "Error requesting config from provider")); 1289 1290 ds->cb (ds->cb_cls, 1291 0, 1292 error_message); 1293 1294 return; 1295 } 1296 1297 /* check if provider index is valid */ 1298 GNUNET_assert (0 < fcfg->provider_index); 1299 GNUNET_assert (ds->dkg_data->num_of_participants >= fcfg->provider_index); 1300 1301 { 1302 /* copy config data to our main struct */ 1303 struct FROSIX_DkgProvider *dp = 1304 &ds->dkg_data->providers[fcfg->provider_index - 1]; 1305 1306 size_t len = strlen (fcfg->business_name); 1307 dp->provider_name = strndup (fcfg->business_name, 1308 len); 1309 1310 memcpy (&dp->provider_salt, 1311 &fcfg->provider_salt, 1312 sizeof (fcfg->provider_salt)); 1313 1314 memcpy (&dp->provider_public_key, 1315 &fcfg->public_key, 1316 sizeof (fcfg->public_key)); 1317 } 1318 1319 ds->counter--; 1320 if (0 == ds->counter) 1321 { 1322 GNUNET_free (ds->co); 1323 ds->co = NULL; 1324 1325 /* we are the last, build array of public keys 1326 and go ahead with the seeds */ 1327 keygen_build_public_key_array (ds->dkg_data); 1328 1329 start_seed_requests (ds); 1330 } 1331 }; 1332 1333 1334 /** 1335 * FIXME 1336 */ 1337 static void 1338 start_config_requests (struct FROSIX_DkgState *ds) 1339 { 1340 ds->counter = 0; 1341 ds->co = GNUNET_malloc (ds->dkg_data->num_of_participants * sizeof (char *)); 1342 1343 for (unsigned int i = 0; i < ds->dkg_data->num_of_participants; i++) 1344 { 1345 ds->dkg_data->providers[i].provider_index = i + 1; 1346 ds->co[i] = FROSIX_get_config (FROSIX_REDUX_ctx_, 1347 ds->dkg_data->providers[i].backend_url, 1348 i + 1, 1349 &config_request_cb, 1350 ds); 1351 ds->counter++; 1352 } 1353 } 1354 1355 1356 /** 1357 * Helper function to parse a keygen input 1358 * 1359 * @param[in,out] dkg_data A initialized struct 1360 * @param[in] arguments Input from the cli 1361 */ 1362 enum GNUNET_GenericReturnValue 1363 parse_keygen_arguments (struct FROSIX_DkgData *dkg_data, 1364 const json_t *arguments) 1365 { 1366 json_t *providers = NULL; 1367 1368 struct GNUNET_JSON_Specification spec[] = { 1369 GNUNET_JSON_spec_uint8 ("threshold", 1370 &dkg_data->threshold), 1371 GNUNET_JSON_spec_uint64 ("expiration", 1372 &dkg_data->expiration), 1373 GNUNET_JSON_spec_json ("providers", 1374 &providers), 1375 GNUNET_JSON_spec_end () 1376 }; 1377 1378 if (GNUNET_OK != GNUNET_JSON_parse (arguments, 1379 spec, 1380 NULL, 1381 NULL)) 1382 { 1383 GNUNET_break (0); 1384 GNUNET_JSON_parse_free (spec); 1385 return GNUNET_NO; 1386 } 1387 1388 /* get number of providers */ 1389 size_t num_of_providers = json_array_size (providers); 1390 1391 /* validate number of providers */ 1392 if (num_of_providers > 254 1393 || num_of_providers < 2 1394 || dkg_data->threshold < 1 1395 || num_of_providers <= dkg_data->threshold) 1396 return GNUNET_NO; 1397 1398 dkg_data->num_of_participants = num_of_providers; 1399 1400 /* initialize providers */ 1401 dkg_data->providers = GNUNET_new_array (dkg_data->num_of_participants, 1402 struct FROSIX_DkgProvider); 1403 1404 /* parse provider data */ 1405 for (unsigned int i = 0; i < dkg_data->num_of_participants; i++) 1406 { 1407 struct GNUNET_JSON_Specification prov_spec[] = { 1408 GNUNET_JSON_spec_string ("url", 1409 (const 1410 char**) &dkg_data->providers[i].backend_url), 1411 GNUNET_JSON_spec_fixed_auto ("public_key", 1412 &dkg_data->providers[i].provider_public_key), 1413 GNUNET_JSON_spec_string ("auth_method", 1414 (const 1415 char**) &dkg_data->providers[i].auth_method), 1416 GNUNET_JSON_spec_string ("auth_data", 1417 (const 1418 char**) &dkg_data->providers[i].auth_data), 1419 GNUNET_JSON_spec_mark_optional ( 1420 GNUNET_JSON_spec_string ("auth_answer", 1421 (const 1422 char**) &dkg_data->providers[i].auth_answer), 1423 NULL), 1424 GNUNET_JSON_spec_end () 1425 }; 1426 1427 if (GNUNET_OK != GNUNET_JSON_parse (json_array_get (providers, 1428 i), 1429 prov_spec, 1430 NULL, 1431 NULL)) 1432 { 1433 GNUNET_break (0); 1434 GNUNET_JSON_parse_free (prov_spec); 1435 GNUNET_JSON_parse_free (spec); 1436 return GNUNET_NO; 1437 } 1438 1439 GNUNET_JSON_parse_free (prov_spec); 1440 } 1441 1442 GNUNET_JSON_parse_free (spec); 1443 return GNUNET_OK; 1444 } 1445 1446 1447 struct FROSIX_ReduxAction * 1448 FROSIX_redux_keygen_start (const json_t *arguments, 1449 FROSIX_ActionCallback cb, 1450 void *cb_cls) 1451 { 1452 /* initialize dkg data struct */ 1453 struct FROSIX_DkgData *dkg_data = GNUNET_new (struct FROSIX_DkgData); 1454 1455 /* parse arguments from cli */ 1456 if (GNUNET_OK != parse_keygen_arguments (dkg_data, 1457 arguments)) 1458 { 1459 free_dkg_data_struct (dkg_data); 1460 GNUNET_free (dkg_data); 1461 json_t *error_message; 1462 error_message = GNUNET_JSON_PACK ( 1463 GNUNET_JSON_pack_string ("Frosix_client_error", 1464 "Error while parsing input")); 1465 1466 cb (cb_cls, 1467 0, 1468 error_message); 1469 1470 return NULL; 1471 } 1472 1473 /* lets create a state */ 1474 struct FROSIX_DkgState *ds = GNUNET_new (struct FROSIX_DkgState); 1475 ds->cb = cb; 1476 ds->cb_cls = cb_cls; 1477 ds->dkg_data = dkg_data; 1478 ds->ra.cleanup = &keygen_cancel_cb; 1479 ds->ra.cleanup_cls = ds; 1480 1481 /* get configs from all parsed providers */ 1482 start_config_requests (ds); 1483 1484 return &ds->ra; 1485 }