frosix_api_sign.c (20473B)
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_sign_redux.c 18 * @brief frosix reducer sign 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 "frost_verify.h" 27 #include "frosix.h" 28 #include "frosix_api.h" 29 #include <taler/taler_merchant_service.h> 30 31 32 /** 33 * FIXME 34 */ 35 struct FROSIX_Provider 36 { 37 /** 38 * URL of the provider. 39 */ 40 char *backend_url; 41 42 /** 43 * Index of the provider 44 */ 45 uint8_t provider_index; 46 47 /** 48 * Authentication data. 49 */ 50 struct GNUNET_HashCode auth_data; 51 52 /** 53 * 54 */ 55 struct GNUNET_CRYPTO_Edx25519PublicKey auth_pub; 56 57 /** 58 * 59 */ 60 struct GNUNET_CRYPTO_Edx25519Signature auth_sig; 61 62 /** 63 * 64 */ 65 const char *auth_method; 66 67 /** 68 * Encryption key 69 */ 70 struct FROSIX_EncryptionKey enc_key; 71 72 /** 73 * Commitment for this signature process. 74 */ 75 struct FROST_Commitment commitment; 76 77 /** 78 * The resulting signature share of this provider. 79 */ 80 struct FROST_SignatureShare sig_share; 81 }; 82 83 /** 84 * Struct to store all parsed data from the cli and /config and /seed 85 */ 86 struct FROSIX_SignatureData 87 { 88 /** 89 * What is the threshold value? 90 */ 91 uint8_t threshold; 92 93 /** 94 * Public key to verify the resulting signature 95 */ 96 struct FROST_PublicKey public_key; 97 98 /** 99 * Our hashed message. 100 */ 101 struct FROST_MessageHash message_hash; 102 103 /** 104 * Pointer to a list of providers, length is @e threshold 105 */ 106 struct FROSIX_Provider *providers; 107 108 /** 109 * Resulting signature 110 */ 111 struct FROST_Signature signature; 112 }; 113 114 /** 115 * State of a sign procedure 116 */ 117 struct FROSIX_SignatureState 118 { 119 /** 120 * State we are updating. 121 */ 122 struct FROSIX_SignatureData *sig_data; 123 124 /** 125 * Function to call when we are done. 126 */ 127 FROSIX_ActionCallback cb; 128 129 /** 130 * Closure for @e cb. 131 */ 132 void *cb_cls; 133 134 /** 135 * Redux action we returned to our controller. 136 */ 137 struct FROSIX_ReduxAction ra; 138 139 /** 140 * Number of provider /config operations in @e ba_head that 141 * are still awaiting completion. 142 */ 143 uint8_t counter; 144 145 /** 146 * Last error code 147 */ 148 enum TALER_ErrorCode error_code; 149 150 /** 151 * Array of config requests, with length `num_of_participants` 152 */ 153 struct FROSIX_ConfigOperation **co; 154 155 /** 156 * Array of signature commitment requests with length @e threshold. 157 */ 158 struct FROSIX_SigCommitmentRequestOperation **sco; 159 160 /** 161 * Array of signature share requests with length @e threshold. 162 */ 163 struct FROSIX_SigShareRequestOperation **sso; 164 165 }; 166 167 168 /** 169 * Function to free all initialized memory of a provider from a 170 * `struct FROSIX_Provider` 171 * 172 * @param fp the struct to clean up 173 */ 174 static void 175 free_provider_struct (struct FROSIX_Provider *fp) 176 { 177 if (NULL != fp->backend_url) 178 GNUNET_free (fp->backend_url); 179 } 180 181 182 /** 183 * Function to free all initialized memory of a provider from a 184 * `struct FROSIX_SignatureData` 185 * 186 * @param dd the struct to clean up 187 */ 188 static void 189 free_signature_data_struct (struct FROSIX_SignatureData *sd) 190 { 191 if (NULL != sd->providers) 192 { 193 for (unsigned int i = 0; i < sd->threshold; i++) 194 { 195 if (NULL != &sd->providers[i]) 196 free_provider_struct (&sd->providers[i]); 197 } 198 199 GNUNET_free (sd->providers); 200 } 201 } 202 203 204 /** 205 * Function called when signature process is being aborted. 206 * Frees all initialized memory! 207 * 208 * @param cls a `struct FROSIX_SignatureState` 209 */ 210 static void 211 sign_cancel_cb (void *cls) 212 { 213 struct FROSIX_SignatureState *ss = cls; 214 215 if (NULL != ss->sig_data) 216 { 217 free_signature_data_struct (ss->sig_data); 218 GNUNET_free (ss->sig_data); 219 } 220 221 222 /* free operations */ 223 if (NULL != ss->co) 224 GNUNET_free (ss->co); 225 226 if (NULL != ss->sco) 227 GNUNET_free (ss->sco); 228 229 if (NULL != ss->sso) 230 GNUNET_free (ss->sso); 231 232 GNUNET_free (ss); 233 234 } 235 236 237 /** 238 * FIXME 239 */ 240 static void 241 check_and_prepare_signature (const struct FROSIX_SignatureState *ss) 242 { 243 /* build array of commitments - needed for verification */ 244 struct FROST_Commitment commitments[ss->sig_data->threshold]; 245 for (unsigned int i = 0; i < ss->sig_data->threshold; i++) 246 { 247 struct FROSIX_Provider *fp = &ss->sig_data->providers[i]; 248 249 commitments[i].identifier = fp->commitment.identifier; 250 251 memcpy (&commitments[i].hiding_commitment, 252 &fp->commitment.hiding_commitment, 253 sizeof (fp->commitment.hiding_commitment)); 254 255 memcpy (&commitments[i].binding_commitment, 256 &fp->commitment.binding_commitment, 257 sizeof (fp->commitment.binding_commitment)); 258 } 259 260 /* verify received signature share */ 261 for (unsigned int i = 0; i < ss->sig_data->threshold; i++) 262 { 263 struct FROSIX_Provider *fp = &ss->sig_data->providers[i]; 264 265 GNUNET_assert (FROST_verify_signature_share ( 266 &fp->commitment, 267 &fp->sig_share, 268 commitments, 269 ss->sig_data->threshold, 270 &ss->sig_data->public_key, 271 &ss->sig_data->message_hash)); 272 } 273 274 /* copy all signature shares together */ 275 struct FROST_SignatureShare sig_shares[ss->sig_data->threshold]; 276 for (unsigned int i = 0; i < ss->sig_data->threshold; i++) 277 { 278 struct FROSIX_Provider *fp = &ss->sig_data->providers[i]; 279 280 sig_shares[i].identifier = fp->sig_share.identifier; 281 282 memcpy (&sig_shares[i].sig_share, 283 &fp->sig_share.sig_share, 284 sizeof (fp->sig_share.sig_share)); 285 286 memcpy (&sig_shares[i].pk_i, 287 &fp->sig_share.pk_i, 288 sizeof (fp->sig_share.pk_i)); 289 } 290 291 /* build signature */ 292 FROST_compose_signature (&ss->sig_data->signature, 293 commitments, 294 sig_shares, 295 ss->sig_data->threshold, 296 &ss->sig_data->message_hash); 297 298 /* verify signature */ 299 GNUNET_assert (FROST_verify_signature (&ss->sig_data->public_key, 300 &ss->sig_data->signature, 301 &ss->sig_data->message_hash)); 302 303 /* build json */ 304 json_t *result; 305 306 result = GNUNET_JSON_PACK ( 307 GNUNET_JSON_pack_data_auto ("message_hash", 308 &ss->sig_data->message_hash), 309 GNUNET_JSON_pack_data_auto ("public_key", 310 &ss->sig_data->public_key), 311 GNUNET_JSON_pack_data_auto ("signature_r", 312 &ss->sig_data->signature.r), 313 GNUNET_JSON_pack_data_auto ("signature_z", 314 &ss->sig_data->signature.z) 315 ); 316 317 /* free all initialized data */ 318 free_signature_data_struct (ss->sig_data); 319 320 ss->cb (ss->cb_cls, 321 ss->error_code, 322 result); 323 } 324 325 326 /** 327 * Callback to process a POST /sig-share request 328 * 329 * @param cls closure 330 * @param ssd the decoded response body 331 */ 332 static void 333 signature_share_request_cb (void *cls, 334 const struct FROSIX_SigShareRequestDetails *ssd) 335 { 336 GNUNET_assert (NULL != cls); 337 struct FROSIX_SignatureState *ss = cls; 338 339 /* set error code */ 340 ss->error_code = ssd->ec; 341 342 /* check if this is a valid callback */ 343 GNUNET_assert (0 < ss->counter); 344 GNUNET_assert (0 != ssd->http_status); 345 346 /* check if provider index is valid */ 347 GNUNET_assert (0 < ssd->sig_share.identifier); 348 GNUNET_assert (255 > ssd->sig_share.identifier); 349 350 struct FROSIX_Provider *fp = &ss->sig_data->providers[ssd->array_index]; 351 352 /* Fill return values in our central struct */ 353 fp->sig_share.identifier = ssd->sig_share.identifier; 354 355 memcpy (&fp->sig_share.sig_share, 356 &ssd->sig_share.sig_share, 357 sizeof (ssd->sig_share.sig_share)); 358 359 memcpy (&fp->sig_share.pk_i, 360 &ssd->sig_share.pk_i, 361 sizeof (ssd->sig_share.pk_i)); 362 363 /* call next dkg-commitment request */ 364 ss->counter--; 365 if (0 == ss->counter) 366 { 367 /* we are the last, check received shares and build final signature */ 368 check_and_prepare_signature (ss); 369 } 370 } 371 372 373 /** 374 * FIXME 375 */ 376 static void 377 start_signature_shares (struct FROSIX_SignatureState *ss) 378 { 379 ss->sso = GNUNET_malloc (ss->sig_data->threshold * sizeof (char *)); 380 ss->counter = 0; 381 382 /* build commitment array */ 383 struct FROST_Commitment commitments[ss->sig_data->threshold]; 384 for (unsigned int i = 0; i < ss->sig_data->threshold; i++) 385 { 386 struct FROSIX_Provider *fp = &ss->sig_data->providers[i]; 387 388 commitments[i].identifier = fp->commitment.identifier; 389 390 FROST_point_copy_to (&commitments[i].hiding_commitment, 391 &fp->commitment.hiding_commitment); 392 393 FROST_point_copy_to (&commitments[i].binding_commitment, 394 &fp->commitment.binding_commitment); 395 } 396 397 for (unsigned int i = 0; i < ss->sig_data->threshold; i++) 398 { 399 struct FROSIX_Provider *fp = &ss->sig_data->providers[i]; 400 401 /* hash encryption key */ 402 struct FROST_HashCode enc_key_hash; 403 FROSIX_hash_encryption_key (&enc_key_hash, 404 &fp->enc_key); 405 406 /* compute request id */ 407 struct FROSIX_SigRequestIdP request_id; 408 FROSIX_compute_signature_request_id ( 409 &request_id, 410 &enc_key_hash, 411 &ss->sig_data->message_hash); 412 413 ss->sso[i] = FROSIX_sig_share_request ( 414 FROSIX_REDUX_ctx_, 415 fp->backend_url, 416 &request_id, 417 fp->provider_index, 418 i, 419 &fp->enc_key, 420 &ss->sig_data->message_hash, 421 commitments, 422 ss->sig_data->threshold, 423 &signature_share_request_cb, 424 ss); 425 426 ss->counter++; 427 } 428 } 429 430 431 432 /** 433 * Callback to process a POST /sig-commitment request 434 * 435 * @param cls closure 436 * @param scd the decoded response body 437 */ 438 static void 439 signature_commitment_request_cb (void *cls, 440 const struct 441 FROSIX_SigCommitmentRequestDetails *scd) 442 { 443 GNUNET_assert (NULL != cls); 444 struct FROSIX_SignatureState *ss = cls; 445 446 /* set error code */ 447 ss->error_code = scd->ec; 448 449 /* check if we have to abort the signing process */ 450 if (0 == scd->http_status) 451 { 452 ss->cb (ss, 453 ss->error_code, 454 NULL); 455 return; 456 } 457 458 459 /* check if this is a valid callback */ 460 GNUNET_assert (0 < ss->counter); 461 462 /* check if provider index is valid */ 463 GNUNET_assert (0 < scd->sig_commitment.identifier); 464 GNUNET_assert (255 > scd->sig_commitment.identifier); 465 466 /* copy commitment in our struct */ 467 struct FROSIX_Provider *fp = &ss->sig_data->providers[scd->array_index]; 468 469 /* Fill return values in our central struct */ 470 fp->commitment.identifier = scd->sig_commitment.identifier; 471 472 FROST_point_copy_to (&fp->commitment.hiding_commitment, 473 &scd->sig_commitment.hiding_commitment); 474 475 FROST_point_copy_to (&fp->commitment.binding_commitment, 476 &scd->sig_commitment.binding_commitment); 477 478 /* call next dkg-commitment request */ 479 ss->counter--; 480 if (0 == ss->counter) 481 { 482 /* we are the last, go ahead with sig-share */ 483 start_signature_shares (ss); 484 } 485 } 486 487 488 /** 489 * FIXME 490 */ 491 static void 492 start_signature_commitments (struct FROSIX_SignatureState *ss) 493 { 494 ss->sco = GNUNET_malloc (ss->sig_data->threshold * sizeof (char *)); 495 ss->counter = 0; 496 for (unsigned int i = 0; i < ss->sig_data->threshold; i++) 497 { 498 struct FROSIX_Provider *fp = &ss->sig_data->providers[i]; 499 500 /* hash encryption key */ 501 struct FROST_HashCode enc_key_hash; 502 FROSIX_hash_encryption_key (&enc_key_hash, 503 &fp->enc_key); 504 505 /* compute request id */ 506 struct FROSIX_SigRequestIdP request_id; 507 FROSIX_compute_signature_request_id ( 508 &request_id, 509 &enc_key_hash, 510 &ss->sig_data->message_hash); 511 512 if (0 == strcmp (fp->auth_method, 513 "question")) 514 { 515 ss->sco[i] = FROSIX_sig_commitment_request ( 516 FROSIX_REDUX_ctx_, 517 fp->backend_url, 518 &request_id, 519 fp->provider_index, 520 i, 521 &enc_key_hash, 522 NULL, 523 &fp->auth_pub, 524 &fp->auth_sig, 525 fp->auth_method, 526 &ss->sig_data->message_hash, 527 &signature_commitment_request_cb, 528 ss); 529 } 530 else 531 { 532 ss->sco[i] = FROSIX_sig_commitment_request ( 533 FROSIX_REDUX_ctx_, 534 fp->backend_url, 535 &request_id, 536 fp->provider_index, 537 i, 538 &enc_key_hash, 539 &fp->auth_data, 540 NULL, 541 NULL, 542 fp->auth_method, 543 &ss->sig_data->message_hash, 544 &signature_commitment_request_cb, 545 ss); 546 } 547 548 549 ss->counter++; 550 } 551 } 552 553 554 /** 555 * Helper function to parse a keygen input 556 * 557 * @param[in,out] dkg_data A initialized struct 558 * @param[in] arguments Input from the cli 559 */ 560 enum GNUNET_GenericReturnValue 561 parse_sign_arguments (struct FROSIX_SignatureData *sig_data, 562 const json_t *arguments, 563 json_t *input) 564 { 565 json_t *providers = NULL; 566 uint8_t max_num = 0; 567 568 struct GNUNET_JSON_Specification spec[] = { 569 GNUNET_JSON_spec_uint8 ("number_of_participants", 570 &max_num), 571 GNUNET_JSON_spec_uint8 ("threshold", 572 &sig_data->threshold), 573 GNUNET_JSON_spec_fixed_auto ("public_key", 574 &sig_data->public_key), 575 GNUNET_JSON_spec_json ("providers", 576 &providers), 577 GNUNET_JSON_spec_end () 578 }; 579 580 if (GNUNET_OK != GNUNET_JSON_parse (arguments, 581 spec, 582 NULL, 583 NULL)) 584 { 585 GNUNET_break (0); 586 GNUNET_JSON_parse_free (spec); 587 return GNUNET_NO; 588 } 589 590 /* get number of providers */ 591 size_t num_of_providers = json_object_size (input); 592 593 /* validate number of providers */ 594 GNUNET_assert (sig_data->threshold == num_of_providers); 595 GNUNET_assert (254 > sig_data->threshold); 596 GNUNET_assert (0 < sig_data->threshold); 597 598 /* initialize providers */ 599 sig_data->providers = GNUNET_new_array (sig_data->threshold, 600 struct FROSIX_Provider); 601 602 uint8_t provider_mapping[sig_data->threshold]; 603 604 /* get involved providers */ 605 const char *key; 606 json_t *value; 607 unsigned int counter = 0; 608 json_object_foreach (input, 609 key, 610 value) 611 { 612 /* try to convert key value (string) to unsigned int */ 613 int key_as_int = atoi (key); 614 615 GNUNET_assert (0 < key_as_int); 616 GNUNET_assert (254 > key_as_int); 617 GNUNET_assert (max_num >= key_as_int); 618 619 provider_mapping[counter] = (uint8_t) key_as_int; 620 counter++; 621 } 622 623 /* parse provider data */ 624 for (unsigned int i = 0; i < sig_data->threshold; i++) 625 { 626 struct GNUNET_HashCode auth_nonce; 627 uint8_t provider_index = provider_mapping[i]; 628 struct GNUNET_JSON_Specification prov_spec[] = { 629 GNUNET_JSON_spec_uint8 ("provider_index", 630 &sig_data->providers[i].provider_index), 631 GNUNET_JSON_spec_string ("backend_url", 632 (const 633 char**) &sig_data->providers[i].backend_url), 634 GNUNET_JSON_spec_fixed_auto ("encryption_key", 635 &sig_data->providers[i].enc_key), 636 GNUNET_JSON_spec_string ("auth_method", 637 &sig_data->providers[i].auth_method), 638 GNUNET_JSON_spec_fixed_auto ("auth_nonce", 639 &auth_nonce), 640 GNUNET_JSON_spec_end () 641 }; 642 643 if (GNUNET_OK != GNUNET_JSON_parse (json_array_get (providers, 644 provider_index - 1), 645 prov_spec, 646 NULL, 647 NULL)) 648 { 649 GNUNET_break (0); 650 GNUNET_JSON_parse_free (prov_spec); 651 GNUNET_JSON_parse_free (spec); 652 return GNUNET_NO; 653 } 654 655 GNUNET_JSON_parse_free (prov_spec); 656 657 /* convert int index to a string - this is our key */ 658 char index[5]; 659 snprintf (index, 660 4, 661 "%d", 662 sig_data->providers[i].provider_index); 663 664 /* parse challenge solution / answer of security question */ 665 if (0 == strcmp (sig_data->providers[i].auth_method, 666 "question")) 667 { 668 const char *answer; 669 670 struct GNUNET_JSON_Specification q_spec[] = { 671 GNUNET_JSON_spec_string (index, 672 &answer), 673 GNUNET_JSON_spec_end () 674 }; 675 676 if (GNUNET_OK != GNUNET_JSON_parse (input, 677 q_spec, 678 NULL, 679 NULL)) 680 { 681 GNUNET_break (0); 682 GNUNET_JSON_parse_free (q_spec); 683 return GNUNET_NO; 684 } 685 686 GNUNET_JSON_parse_free (q_spec); 687 688 unsigned int amplifier = 1; 689 /* compute key pair to sign signature */ 690 struct GNUNET_CRYPTO_Edx25519PrivateKey priv; 691 struct FROSIX_ChallengeHashP auth_hash; 692 FROSIX_hash_pow (&auth_hash.hash, 693 &priv, 694 &sig_data->providers[i].auth_pub, 695 &auth_nonce, 696 answer, 697 amplifier); 698 699 // Sign data 700 struct FROSIX_AuthSignaturePS as = { 701 .purpose.purpose = htonl (72), 702 .purpose.size = htonl (sizeof (as)), 703 .mh = sig_data->message_hash, 704 }; 705 706 GNUNET_CRYPTO_edx25519_sign (&priv, 707 &as, 708 &sig_data->providers[i].auth_sig); 709 } 710 else 711 { 712 /* parse answer as number */ 713 uint64_t code; 714 715 struct GNUNET_JSON_Specification c_spec[] = { 716 GNUNET_JSON_spec_uint64 (index, 717 &code), 718 GNUNET_JSON_spec_end () 719 }; 720 721 if (GNUNET_OK != GNUNET_JSON_parse (input, 722 c_spec, 723 NULL, 724 NULL)) 725 { 726 GNUNET_break (0); 727 GNUNET_JSON_parse_free (c_spec); 728 return GNUNET_NO; 729 } 730 731 GNUNET_JSON_parse_free (c_spec); 732 733 /* compute challenge hash */ 734 FROSIX_hash_answer (code, 735 &sig_data->providers[i].auth_data); 736 } 737 } 738 739 GNUNET_JSON_parse_free (spec); 740 741 /* check if list of providers is sorted */ 742 for (unsigned int i = 1; i < sig_data->threshold; i++) 743 { 744 GNUNET_assert (sig_data->providers[i].provider_index > 745 sig_data->providers[i - 1].provider_index); 746 } 747 748 return GNUNET_OK; 749 } 750 751 752 /** 753 * 754 */ 755 struct FROSIX_ReduxAction * 756 FROSIX_redux_sign_start (const json_t *arguments, 757 json_t *input, 758 const char *message, 759 FROSIX_ActionCallback cb, 760 void *cb_cls) 761 { 762 /* initialize signature data struct */ 763 struct FROSIX_SignatureData *sig_data = GNUNET_new (struct 764 FROSIX_SignatureData); 765 766 /* hash message */ 767 FROST_message_to_hash (&sig_data->message_hash, 768 message, 769 strlen (message)); 770 771 /* parse arguments from cli */ 772 if (GNUNET_OK != parse_sign_arguments (sig_data, 773 arguments, 774 input)) 775 { 776 free_signature_data_struct (sig_data); 777 778 // FIXME: Return some useful error message 779 return NULL; 780 } 781 782 /* lets create a state */ 783 struct FROSIX_SignatureState *ss = GNUNET_new (struct FROSIX_SignatureState); 784 ss->cb = cb; 785 ss->cb_cls = cb_cls; 786 ss->sig_data = sig_data; 787 ss->ra.cleanup = &sign_cancel_cb; 788 ss->ra.cleanup_cls = ss; 789 790 /* get commitments from all parsed providers */ 791 start_signature_commitments (ss); 792 793 return &ss->ra; 794 }