diff options
Diffstat (limited to 'src/mint/taler-mint-httpd_refresh.c')
-rw-r--r-- | src/mint/taler-mint-httpd_refresh.c | 370 |
1 files changed, 51 insertions, 319 deletions
diff --git a/src/mint/taler-mint-httpd_refresh.c b/src/mint/taler-mint-httpd_refresh.c index fc46a1d35..69ba87c29 100644 --- a/src/mint/taler-mint-httpd_refresh.c +++ b/src/mint/taler-mint-httpd_refresh.c | |||
@@ -483,6 +483,7 @@ TALER_MINT_handler_refresh_commit (struct RequestHandler *rh, | |||
483 | return MHD_NO; | 483 | return MHD_NO; |
484 | } | 484 | } |
485 | res = GNUNET_MINT_parse_navigate_json (connection, root, | 485 | res = GNUNET_MINT_parse_navigate_json (connection, root, |
486 | JNAV_FIELD, "coin_evs", | ||
486 | JNAV_INDEX, (int) 0, | 487 | JNAV_INDEX, (int) 0, |
487 | JNAV_RET_DATA, | 488 | JNAV_RET_DATA, |
488 | JSON_ARRAY, &coin_detail); | 489 | JSON_ARRAY, &coin_detail); |
@@ -502,6 +503,7 @@ TALER_MINT_handler_refresh_commit (struct RequestHandler *rh, | |||
502 | return MHD_NO; | 503 | return MHD_NO; |
503 | } | 504 | } |
504 | res = GNUNET_MINT_parse_navigate_json (connection, root, | 505 | res = GNUNET_MINT_parse_navigate_json (connection, root, |
506 | JNAV_FIELD, "transfer_pubs", | ||
505 | JNAV_INDEX, (int) 0, | 507 | JNAV_INDEX, (int) 0, |
506 | JNAV_RET_DATA, | 508 | JNAV_RET_DATA, |
507 | JSON_ARRAY, &coin_detail); | 509 | JSON_ARRAY, &coin_detail); |
@@ -653,59 +655,6 @@ TALER_MINT_handler_refresh_commit (struct RequestHandler *rh, | |||
653 | 655 | ||
654 | 656 | ||
655 | /** | 657 | /** |
656 | * Send response for "/refresh/reveal". | ||
657 | * | ||
658 | * @param connection the MHD connection | ||
659 | * @param db_conn the connection to the mint's db | ||
660 | * @param refresh_session_pub the refresh session's public key | ||
661 | * @return a MHD result code | ||
662 | */ | ||
663 | static int | ||
664 | helper_refresh_reveal_send_response (struct MHD_Connection *connection, | ||
665 | PGconn *db_conn, | ||
666 | struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub) | ||
667 | { | ||
668 | int res; | ||
669 | int newcoin_index; | ||
670 | struct RefreshSession refresh_session; | ||
671 | struct TALER_RSA_Signature *sigs; | ||
672 | |||
673 | res = TALER_MINT_DB_get_refresh_session (db_conn, | ||
674 | refresh_session_pub, | ||
675 | &refresh_session); | ||
676 | if (GNUNET_OK != res) | ||
677 | { | ||
678 | // FIXME: return 'internal error' | ||
679 | GNUNET_break (0); | ||
680 | return MHD_NO; | ||
681 | } | ||
682 | |||
683 | GNUNET_assert (0 != refresh_session.reveal_ok); | ||
684 | sigs = GNUNET_malloc (refresh_session.num_newcoins * | ||
685 | sizeof (struct TALER_RSA_Signature)); | ||
686 | for (newcoin_index = 0; newcoin_index < refresh_session.num_newcoins; newcoin_index++) | ||
687 | { | ||
688 | res = TALER_MINT_DB_get_refresh_collectable (db_conn, | ||
689 | newcoin_index, | ||
690 | refresh_session_pub, | ||
691 | &sigs[newcoin_index]); | ||
692 | if (GNUNET_OK != res) | ||
693 | { | ||
694 | // FIXME: return 'internal error' | ||
695 | GNUNET_break (0); | ||
696 | GNUNET_free (sigs); | ||
697 | return MHD_NO; | ||
698 | } | ||
699 | } | ||
700 | res = TALER_MINT_reply_refresh_reveal_success (connection, | ||
701 | refresh_session.num_newcoins, | ||
702 | sigs); | ||
703 | GNUNET_free (sigs); | ||
704 | return res; | ||
705 | } | ||
706 | |||
707 | |||
708 | /** | ||
709 | * Handle a "/refresh/reveal" request | 658 | * Handle a "/refresh/reveal" request |
710 | * | 659 | * |
711 | * @param rh context of the handler | 660 | * @param rh context of the handler |
@@ -724,12 +673,14 @@ TALER_MINT_handler_refresh_reveal (struct RequestHandler *rh, | |||
724 | { | 673 | { |
725 | struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub; | 674 | struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub; |
726 | int res; | 675 | int res; |
727 | PGconn *db_conn; | 676 | unsigned int kappa; |
728 | struct RefreshSession refresh_session; | 677 | unsigned int num_oldcoins; |
729 | struct MintKeyState *key_state; | 678 | json_t *transfer_p; |
730 | int i; | 679 | json_t *reveal_detail; |
731 | int j; | 680 | unsigned int i; |
681 | unsigned int j; | ||
732 | json_t *root; | 682 | json_t *root; |
683 | struct GNUNET_CRYPTO_EcdsaPrivateKey **transfer_privs; | ||
733 | 684 | ||
734 | res = TALER_MINT_parse_post_json (connection, | 685 | res = TALER_MINT_parse_post_json (connection, |
735 | connection_cls, | 686 | connection_cls, |
@@ -753,279 +704,60 @@ TALER_MINT_handler_refresh_reveal (struct RequestHandler *rh, | |||
753 | } | 704 | } |
754 | 705 | ||
755 | 706 | ||
756 | 707 | /* Determine dimensionality of the request (kappa and #old coins) */ | |
757 | if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) | 708 | res = GNUNET_MINT_parse_navigate_json (connection, root, |
758 | { | 709 | JNAV_FIELD, "transfer_privs", |
759 | GNUNET_break (0); | 710 | JNAV_RET_TYPED_JSON, JSON_ARRAY, &transfer_p); |
760 | // FIXME: return 'internal error'? | 711 | if (GNUNET_OK != res) |
761 | return MHD_NO; | 712 | return res; |
762 | } | 713 | kappa = json_array_size (transfer_p) + 1; /* 1 row is missing */ |
763 | 714 | if (3 > kappa) | |
764 | /* Send response immediately if we already know the session, | ||
765 | * and the session commited already. | ||
766 | * Do _not_ care about fields other than session_pub in this case. */ | ||
767 | |||
768 | res = TALER_MINT_DB_get_refresh_session (db_conn, | ||
769 | &refresh_session_pub, | ||
770 | &refresh_session); | ||
771 | if (GNUNET_YES == res && 0 != refresh_session.reveal_ok) | ||
772 | return helper_refresh_reveal_send_response (connection, | ||
773 | db_conn, | ||
774 | &refresh_session_pub); | ||
775 | if (GNUNET_SYSERR == res) | ||
776 | { | 715 | { |
777 | GNUNET_break (0); | 716 | GNUNET_break_op (0); |
778 | // FIXME: return 'internal error'? | 717 | // FIXME: generate error message |
779 | return MHD_NO; | 718 | return MHD_NO; |
780 | } | 719 | } |
720 | res = GNUNET_MINT_parse_navigate_json (connection, root, | ||
721 | JNAV_FIELD, "transfer_privs", | ||
722 | JNAV_INDEX, 0, | ||
723 | JNAV_RET_TYPED_JSON, JSON_ARRAY, &reveal_detail); | ||
724 | if (GNUNET_OK != res) | ||
725 | return res; | ||
726 | num_oldcoins = json_array_size (reveal_detail); | ||
781 | 727 | ||
782 | /* Check that the transfer private keys match their commitments. | ||
783 | * Then derive the shared secret for each kappa, and check that they match. */ | ||
784 | 728 | ||
785 | for (i = 0; i < refresh_session.kappa; i++) | 729 | transfer_privs = GNUNET_malloc ((kappa - 1) * |
730 | sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey *)); | ||
731 | for (i = 0; i < kappa - 1; i++) | ||
786 | { | 732 | { |
787 | struct GNUNET_HashCode last_shared_secret; | 733 | transfer_privs[i] = GNUNET_malloc (num_oldcoins * |
788 | int secret_initialized = GNUNET_NO; | 734 | sizeof (struct GNUNET_CRYPTO_EcdsaPrivateKey)); |
789 | 735 | for (j = 0; j < num_oldcoins; j++) | |
790 | if (i == (refresh_session.noreveal_index % refresh_session.kappa)) | ||
791 | continue; | ||
792 | |||
793 | for (j = 0; j < refresh_session.num_oldcoins; j++) | ||
794 | { | ||
795 | struct GNUNET_CRYPTO_EcdsaPrivateKey transfer_priv; | ||
796 | struct RefreshCommitLink commit_link; | ||
797 | struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub; | ||
798 | struct GNUNET_HashCode transfer_secret; | ||
799 | struct GNUNET_HashCode shared_secret; | ||
800 | |||
801 | res = GNUNET_MINT_parse_navigate_json (connection, root, | ||
802 | JNAV_FIELD, "transfer_privs", | ||
803 | JNAV_INDEX, (int) i, | ||
804 | JNAV_INDEX, (int) j, | ||
805 | JNAV_RET_DATA, | ||
806 | &transfer_priv, | ||
807 | sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)); | ||
808 | |||
809 | if (GNUNET_OK != res) | ||
810 | { | ||
811 | GNUNET_break (GNUNET_SYSERR != res); | ||
812 | return res; | ||
813 | } | ||
814 | |||
815 | res = TALER_MINT_DB_get_refresh_commit_link (db_conn, | ||
816 | &refresh_session_pub, | ||
817 | i, j, | ||
818 | &commit_link); | ||
819 | if (GNUNET_OK != res) | ||
820 | { | 736 | { |
821 | GNUNET_break (0); | 737 | res = GNUNET_MINT_parse_navigate_json (connection, root, |
738 | JNAV_FIELD, "transfer_privs", | ||
739 | JNAV_INDEX, (int) i, | ||
740 | JNAV_INDEX, (int) j, | ||
741 | JNAV_RET_DATA, | ||
742 | &transfer_privs[i][j], | ||
743 | sizeof (struct GNUNET_CRYPTO_EddsaPrivateKey)); | ||
744 | if (GNUNET_OK != res) | ||
745 | { | ||
746 | GNUNET_break (0); | ||
822 | // FIXME: return 'internal error'? | 747 | // FIXME: return 'internal error'? |
823 | return MHD_NO; | 748 | return MHD_NO; |
749 | } | ||
824 | } | 750 | } |
825 | |||
826 | res = TALER_MINT_DB_get_refresh_melt (db_conn, &refresh_session_pub, j, &coin_pub); | ||
827 | if (GNUNET_OK != res) | ||
828 | { | ||
829 | GNUNET_break (0); | ||
830 | // FIXME: return 'internal error'? | ||
831 | return MHD_NO; | ||
832 | } | ||
833 | |||
834 | /* We're converting key types here, which is not very nice | ||
835 | * but necessary and harmless (keys will be thrown away later). */ | ||
836 | if (GNUNET_OK != GNUNET_CRYPTO_ecc_ecdh ((struct GNUNET_CRYPTO_EcdhePrivateKey *) &transfer_priv, | ||
837 | (struct GNUNET_CRYPTO_EcdhePublicKey *) &coin_pub, | ||
838 | &transfer_secret)) | ||
839 | { | ||
840 | GNUNET_break (0); | ||
841 | // FIXME: return 'internal error'? | ||
842 | return MHD_NO; | ||
843 | } | ||
844 | |||
845 | if (0 >= TALER_refresh_decrypt (commit_link.shared_secret_enc, TALER_REFRESH_SHARED_SECRET_LENGTH, | ||
846 | &transfer_secret, &shared_secret)) | ||
847 | { | ||
848 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decryption failed\n"); | ||
849 | // FIXME: return 'internal error'? | ||
850 | return MHD_NO; | ||
851 | } | ||
852 | |||
853 | if (GNUNET_NO == secret_initialized) | ||
854 | { | ||
855 | secret_initialized = GNUNET_YES; | ||
856 | last_shared_secret = shared_secret; | ||
857 | } | ||
858 | else if (0 != memcmp (&shared_secret, &last_shared_secret, sizeof (struct GNUNET_HashCode))) | ||
859 | { | ||
860 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "shared secrets do not match\n"); | ||
861 | // FIXME: return error code! | ||
862 | return MHD_NO; | ||
863 | } | ||
864 | |||
865 | { | ||
866 | struct GNUNET_CRYPTO_EcdsaPublicKey transfer_pub_check; | ||
867 | GNUNET_CRYPTO_ecdsa_key_get_public (&transfer_priv, &transfer_pub_check); | ||
868 | if (0 != memcmp (&transfer_pub_check, &commit_link.transfer_pub, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) | ||
869 | { | ||
870 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "transfer keys do not match\n"); | ||
871 | // FIXME: return error code! | ||
872 | return MHD_NO; | ||
873 | } | ||
874 | } | ||
875 | } | ||
876 | |||
877 | /* Check that the commitments for all new coins were correct */ | ||
878 | |||
879 | for (j = 0; j < refresh_session.num_newcoins; j++) | ||
880 | { | ||
881 | struct RefreshCommitCoin commit_coin; | ||
882 | struct LinkData link_data; | ||
883 | struct TALER_RSA_BlindedSignaturePurpose *coin_ev_check; | ||
884 | struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub; | ||
885 | struct TALER_RSA_BlindingKey *bkey; | ||
886 | struct TALER_RSA_PublicKeyBinaryEncoded denom_pub; | ||
887 | |||
888 | bkey = NULL; | ||
889 | res = TALER_MINT_DB_get_refresh_commit_coin (db_conn, | ||
890 | &refresh_session_pub, | ||
891 | i, j, | ||
892 | &commit_coin); | ||
893 | if (GNUNET_OK != res) | ||
894 | { | ||
895 | GNUNET_break (0); | ||
896 | // FIXME: return error code! | ||
897 | return MHD_NO; | ||
898 | } | ||
899 | |||
900 | |||
901 | if (0 >= TALER_refresh_decrypt (commit_coin.link_enc, sizeof (struct LinkData), | ||
902 | &last_shared_secret, &link_data)) | ||
903 | { | ||
904 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decryption failed\n"); | ||
905 | // FIXME: return error code! | ||
906 | return MHD_NO; | ||
907 | } | ||
908 | |||
909 | GNUNET_CRYPTO_ecdsa_key_get_public (&link_data.coin_priv, &coin_pub); | ||
910 | if (NULL == (bkey = TALER_RSA_blinding_key_decode (&link_data.bkey_enc))) | ||
911 | { | ||
912 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid blinding key\n"); | ||
913 | // FIXME: return error code! | ||
914 | return MHD_NO; | ||
915 | } | ||
916 | res = TALER_MINT_DB_get_refresh_order (db_conn, j, &refresh_session_pub, &denom_pub); | ||
917 | if (GNUNET_OK != res) | ||
918 | { | ||
919 | GNUNET_break (0); | ||
920 | // FIXME: return error code! | ||
921 | return MHD_NO; | ||
922 | } | ||
923 | if (NULL == (coin_ev_check = | ||
924 | TALER_RSA_message_blind (&coin_pub, | ||
925 | sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey), | ||
926 | bkey, | ||
927 | &denom_pub))) | ||
928 | { | ||
929 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "blind failed\n"); | ||
930 | // FIXME: return error code! | ||
931 | return MHD_NO; | ||
932 | } | ||
933 | |||
934 | if (0 != memcmp (&coin_ev_check, | ||
935 | &commit_coin.coin_ev, | ||
936 | sizeof (struct TALER_RSA_BlindedSignaturePurpose))) | ||
937 | { | ||
938 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "blind envelope does not match for kappa=%d, old=%d\n", | ||
939 | (int) i, (int) j); | ||
940 | // FIXME: return error code! | ||
941 | return MHD_NO; | ||
942 | } | ||
943 | } | ||
944 | } | 751 | } |
945 | 752 | ||
946 | 753 | ||
947 | if (GNUNET_OK != TALER_MINT_DB_transaction (db_conn)) | 754 | res = TALER_MINT_db_execute_refresh_reveal (connection, |
948 | { | 755 | &refresh_session_pub, |
949 | GNUNET_break (0); | 756 | kappa, |
950 | // FIXME: return error code! | 757 | num_oldcoins, |
951 | return MHD_NO; | 758 | transfer_privs); |
952 | } | 759 | // FIXME: free memory |
953 | 760 | return res; | |
954 | for (j = 0; j < refresh_session.num_newcoins; j++) | ||
955 | { | ||
956 | struct RefreshCommitCoin commit_coin; | ||
957 | struct TALER_RSA_PublicKeyBinaryEncoded denom_pub; | ||
958 | struct TALER_MINT_DenomKeyIssuePriv *dki; | ||
959 | struct TALER_RSA_Signature ev_sig; | ||
960 | |||
961 | res = TALER_MINT_DB_get_refresh_commit_coin (db_conn, | ||
962 | &refresh_session_pub, | ||
963 | refresh_session.noreveal_index % refresh_session.kappa, | ||
964 | j, | ||
965 | &commit_coin); | ||
966 | if (GNUNET_OK != res) | ||
967 | { | ||
968 | GNUNET_break (0); | ||
969 | // FIXME: return error code! | ||
970 | return MHD_NO; | ||
971 | } | ||
972 | res = TALER_MINT_DB_get_refresh_order (db_conn, j, &refresh_session_pub, &denom_pub); | ||
973 | if (GNUNET_OK != res) | ||
974 | { | ||
975 | GNUNET_break (0); | ||
976 | // FIXME: return error code! | ||
977 | return MHD_NO; | ||
978 | } | ||
979 | |||
980 | |||
981 | key_state = TALER_MINT_key_state_acquire (); | ||
982 | dki = TALER_MINT_get_denom_key (key_state, &denom_pub); | ||
983 | TALER_MINT_key_state_release (key_state); | ||
984 | if (NULL == dki) | ||
985 | { | ||
986 | GNUNET_break (0); | ||
987 | // FIXME: return error code! | ||
988 | return MHD_NO; | ||
989 | } | ||
990 | if (GNUNET_OK != | ||
991 | TALER_RSA_sign (dki->denom_priv, | ||
992 | &commit_coin.coin_ev, | ||
993 | sizeof (struct TALER_RSA_BlindedSignaturePurpose), | ||
994 | &ev_sig)) | ||
995 | { | ||
996 | GNUNET_break (0); | ||
997 | // FIXME: return error code! | ||
998 | return MHD_NO; | ||
999 | } | ||
1000 | |||
1001 | res = TALER_MINT_DB_insert_refresh_collectable (db_conn, | ||
1002 | j, | ||
1003 | &refresh_session_pub, | ||
1004 | &ev_sig); | ||
1005 | if (GNUNET_OK != res) | ||
1006 | { | ||
1007 | GNUNET_break (0); | ||
1008 | // FIXME: return error code! | ||
1009 | return MHD_NO; | ||
1010 | } | ||
1011 | } | ||
1012 | /* mark that reveal was successful */ | ||
1013 | |||
1014 | res = TALER_MINT_DB_set_reveal_ok (db_conn, &refresh_session_pub); | ||
1015 | if (GNUNET_OK != res) | ||
1016 | { | ||
1017 | GNUNET_break (0); | ||
1018 | // FIXME: return error code! | ||
1019 | return MHD_NO; | ||
1020 | } | ||
1021 | |||
1022 | if (GNUNET_OK != TALER_MINT_DB_commit (db_conn)) | ||
1023 | { | ||
1024 | GNUNET_break (0); | ||
1025 | return MHD_NO; | ||
1026 | } | ||
1027 | |||
1028 | return helper_refresh_reveal_send_response (connection, db_conn, &refresh_session_pub); | ||
1029 | } | 761 | } |
1030 | 762 | ||
1031 | 763 | ||