diff options
Diffstat (limited to 'src/mint/taler-mint-httpd_db.c')
-rw-r--r-- | src/mint/taler-mint-httpd_db.c | 343 |
1 files changed, 340 insertions, 3 deletions
diff --git a/src/mint/taler-mint-httpd_db.c b/src/mint/taler-mint-httpd_db.c index bcdda621a..a581d486b 100644 --- a/src/mint/taler-mint-httpd_db.c +++ b/src/mint/taler-mint-httpd_db.c | |||
@@ -794,8 +794,6 @@ TALER_MINT_db_execute_refresh_commit (struct MHD_Connection *connection, | |||
794 | return MHD_NO; | 794 | return MHD_NO; |
795 | } | 795 | } |
796 | 796 | ||
797 | |||
798 | |||
799 | if (GNUNET_OK != TALER_MINT_DB_commit (db_conn)) | 797 | if (GNUNET_OK != TALER_MINT_DB_commit (db_conn)) |
800 | { | 798 | { |
801 | // FIXME: return 'internal error'? | 799 | // FIXME: return 'internal error'? |
@@ -804,7 +802,346 @@ TALER_MINT_db_execute_refresh_commit (struct MHD_Connection *connection, | |||
804 | } | 802 | } |
805 | 803 | ||
806 | return TALER_MINT_reply_refresh_commit_success (connection, &refresh_session); | 804 | return TALER_MINT_reply_refresh_commit_success (connection, &refresh_session); |
807 | } | 805 | } |
806 | |||
807 | |||
808 | /** | ||
809 | * Send response for "/refresh/reveal". | ||
810 | * | ||
811 | * @param connection the MHD connection | ||
812 | * @param db_conn the connection to the mint's db | ||
813 | * @param refresh_session_pub the refresh session's public key | ||
814 | * @return a MHD result code | ||
815 | */ | ||
816 | static int | ||
817 | helper_refresh_reveal_send_response (struct MHD_Connection *connection, | ||
818 | PGconn *db_conn, | ||
819 | const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub) | ||
820 | { | ||
821 | int res; | ||
822 | int newcoin_index; | ||
823 | struct RefreshSession refresh_session; | ||
824 | struct TALER_RSA_Signature *sigs; | ||
825 | |||
826 | res = TALER_MINT_DB_get_refresh_session (db_conn, | ||
827 | refresh_session_pub, | ||
828 | &refresh_session); | ||
829 | if (GNUNET_OK != res) | ||
830 | { | ||
831 | // FIXME: return 'internal error' | ||
832 | GNUNET_break (0); | ||
833 | return MHD_NO; | ||
834 | } | ||
835 | |||
836 | GNUNET_assert (0 != refresh_session.reveal_ok); | ||
837 | sigs = GNUNET_malloc (refresh_session.num_newcoins * | ||
838 | sizeof (struct TALER_RSA_Signature)); | ||
839 | for (newcoin_index = 0; newcoin_index < refresh_session.num_newcoins; newcoin_index++) | ||
840 | { | ||
841 | res = TALER_MINT_DB_get_refresh_collectable (db_conn, | ||
842 | newcoin_index, | ||
843 | refresh_session_pub, | ||
844 | &sigs[newcoin_index]); | ||
845 | if (GNUNET_OK != res) | ||
846 | { | ||
847 | // FIXME: return 'internal error' | ||
848 | GNUNET_break (0); | ||
849 | GNUNET_free (sigs); | ||
850 | return MHD_NO; | ||
851 | } | ||
852 | } | ||
853 | res = TALER_MINT_reply_refresh_reveal_success (connection, | ||
854 | refresh_session.num_newcoins, | ||
855 | sigs); | ||
856 | GNUNET_free (sigs); | ||
857 | return res; | ||
858 | } | ||
859 | |||
860 | |||
861 | /** | ||
862 | * Execute a /refresh/reveal. | ||
863 | * | ||
864 | * @param connection the MHD connection to handle | ||
865 | * @param refresh_session_pub public key of the refresh session | ||
866 | * @param kappa size of x-dimension of @transfer_privs array plus one (!) | ||
867 | * @param num_oldcoins size of y-dimension of @transfer_privs array | ||
868 | * @param transfer_pubs array with the revealed transfer keys | ||
869 | * @return MHD result code | ||
870 | */ | ||
871 | int | ||
872 | TALER_MINT_db_execute_refresh_reveal (struct MHD_Connection *connection, | ||
873 | const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub, | ||
874 | unsigned int kappa, | ||
875 | unsigned int num_oldcoins, | ||
876 | struct GNUNET_CRYPTO_EcdsaPrivateKey *const*transfer_privs) | ||
877 | { | ||
878 | int res; | ||
879 | PGconn *db_conn; | ||
880 | struct RefreshSession refresh_session; | ||
881 | struct MintKeyState *key_state; | ||
882 | unsigned int i; | ||
883 | unsigned int j; | ||
884 | unsigned int off; | ||
885 | |||
886 | if (NULL == (db_conn = TALER_MINT_DB_get_connection ())) | ||
887 | { | ||
888 | GNUNET_break (0); | ||
889 | // FIXME: return 'internal error'? | ||
890 | return MHD_NO; | ||
891 | } | ||
892 | |||
893 | /* Send response immediately if we already know the session, | ||
894 | * and the session commited already. | ||
895 | * Do _not_ care about fields other than session_pub in this case. */ | ||
896 | |||
897 | res = TALER_MINT_DB_get_refresh_session (db_conn, | ||
898 | refresh_session_pub, | ||
899 | &refresh_session); | ||
900 | if (GNUNET_YES == res && 0 != refresh_session.reveal_ok) | ||
901 | return helper_refresh_reveal_send_response (connection, | ||
902 | db_conn, | ||
903 | refresh_session_pub); | ||
904 | if (GNUNET_SYSERR == res) | ||
905 | { | ||
906 | GNUNET_break (0); | ||
907 | // FIXME: return 'internal error'? | ||
908 | return MHD_NO; | ||
909 | } | ||
910 | |||
911 | /* Check that the transfer private keys match their commitments. | ||
912 | * Then derive the shared secret for each kappa, and check that they match. */ | ||
913 | |||
914 | off = 0; | ||
915 | for (i = 0; i < refresh_session.kappa - 1; i++) | ||
916 | { | ||
917 | struct GNUNET_HashCode last_shared_secret; | ||
918 | int secret_initialized = GNUNET_NO; | ||
919 | |||
920 | if (i == refresh_session.noreveal_index) | ||
921 | off = 1; | ||
922 | |||
923 | for (j = 0; j < refresh_session.num_oldcoins; j++) | ||
924 | { | ||
925 | struct RefreshCommitLink commit_link; | ||
926 | struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub; | ||
927 | struct GNUNET_HashCode transfer_secret; | ||
928 | struct GNUNET_HashCode shared_secret; | ||
929 | |||
930 | res = TALER_MINT_DB_get_refresh_commit_link (db_conn, | ||
931 | refresh_session_pub, | ||
932 | i + off, j, | ||
933 | &commit_link); | ||
934 | if (GNUNET_OK != res) | ||
935 | { | ||
936 | GNUNET_break (0); | ||
937 | // FIXME: return 'internal error'? | ||
938 | return MHD_NO; | ||
939 | } | ||
940 | |||
941 | res = TALER_MINT_DB_get_refresh_melt (db_conn, refresh_session_pub, j, &coin_pub); | ||
942 | if (GNUNET_OK != res) | ||
943 | { | ||
944 | GNUNET_break (0); | ||
945 | // FIXME: return 'internal error'? | ||
946 | return MHD_NO; | ||
947 | } | ||
948 | |||
949 | /* We're converting key types here, which is not very nice | ||
950 | * but necessary and harmless (keys will be thrown away later). */ | ||
951 | if (GNUNET_OK != GNUNET_CRYPTO_ecc_ecdh ((struct GNUNET_CRYPTO_EcdhePrivateKey *) &transfer_privs[i+off][j], | ||
952 | (struct GNUNET_CRYPTO_EcdhePublicKey *) &coin_pub, | ||
953 | &transfer_secret)) | ||
954 | { | ||
955 | GNUNET_break (0); | ||
956 | // FIXME: return 'internal error'? | ||
957 | return MHD_NO; | ||
958 | } | ||
959 | |||
960 | if (0 >= TALER_refresh_decrypt (commit_link.shared_secret_enc, TALER_REFRESH_SHARED_SECRET_LENGTH, | ||
961 | &transfer_secret, &shared_secret)) | ||
962 | { | ||
963 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decryption failed\n"); | ||
964 | // FIXME: return 'internal error'? | ||
965 | return MHD_NO; | ||
966 | } | ||
967 | |||
968 | if (GNUNET_NO == secret_initialized) | ||
969 | { | ||
970 | secret_initialized = GNUNET_YES; | ||
971 | last_shared_secret = shared_secret; | ||
972 | } | ||
973 | else if (0 != memcmp (&shared_secret, &last_shared_secret, sizeof (struct GNUNET_HashCode))) | ||
974 | { | ||
975 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "shared secrets do not match\n"); | ||
976 | // FIXME: return error code! | ||
977 | return MHD_NO; | ||
978 | } | ||
979 | |||
980 | { | ||
981 | struct GNUNET_CRYPTO_EcdsaPublicKey transfer_pub_check; | ||
982 | GNUNET_CRYPTO_ecdsa_key_get_public (&transfer_privs[i+off][j], &transfer_pub_check); | ||
983 | if (0 != memcmp (&transfer_pub_check, &commit_link.transfer_pub, sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey))) | ||
984 | { | ||
985 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "transfer keys do not match\n"); | ||
986 | // FIXME: return error code! | ||
987 | return MHD_NO; | ||
988 | } | ||
989 | } | ||
990 | } | ||
991 | |||
992 | /* Check that the commitments for all new coins were correct */ | ||
993 | |||
994 | for (j = 0; j < refresh_session.num_newcoins; j++) | ||
995 | { | ||
996 | struct RefreshCommitCoin commit_coin; | ||
997 | struct LinkData link_data; | ||
998 | struct TALER_RSA_BlindedSignaturePurpose *coin_ev_check; | ||
999 | struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub; | ||
1000 | struct TALER_RSA_BlindingKey *bkey; | ||
1001 | struct TALER_RSA_PublicKeyBinaryEncoded denom_pub; | ||
1002 | |||
1003 | bkey = NULL; | ||
1004 | res = TALER_MINT_DB_get_refresh_commit_coin (db_conn, | ||
1005 | refresh_session_pub, | ||
1006 | i+off, j, | ||
1007 | &commit_coin); | ||
1008 | if (GNUNET_OK != res) | ||
1009 | { | ||
1010 | GNUNET_break (0); | ||
1011 | // FIXME: return error code! | ||
1012 | return MHD_NO; | ||
1013 | } | ||
1014 | |||
1015 | |||
1016 | if (0 >= TALER_refresh_decrypt (commit_coin.link_enc, sizeof (struct LinkData), | ||
1017 | &last_shared_secret, &link_data)) | ||
1018 | { | ||
1019 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "decryption failed\n"); | ||
1020 | // FIXME: return error code! | ||
1021 | return MHD_NO; | ||
1022 | } | ||
1023 | |||
1024 | GNUNET_CRYPTO_ecdsa_key_get_public (&link_data.coin_priv, &coin_pub); | ||
1025 | if (NULL == (bkey = TALER_RSA_blinding_key_decode (&link_data.bkey_enc))) | ||
1026 | { | ||
1027 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid blinding key\n"); | ||
1028 | // FIXME: return error code! | ||
1029 | return MHD_NO; | ||
1030 | } | ||
1031 | res = TALER_MINT_DB_get_refresh_order (db_conn, j, refresh_session_pub, &denom_pub); | ||
1032 | if (GNUNET_OK != res) | ||
1033 | { | ||
1034 | GNUNET_break (0); | ||
1035 | // FIXME: return error code! | ||
1036 | return MHD_NO; | ||
1037 | } | ||
1038 | if (NULL == (coin_ev_check = | ||
1039 | TALER_RSA_message_blind (&coin_pub, | ||
1040 | sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey), | ||
1041 | bkey, | ||
1042 | &denom_pub))) | ||
1043 | { | ||
1044 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "blind failed\n"); | ||
1045 | // FIXME: return error code! | ||
1046 | return MHD_NO; | ||
1047 | } | ||
1048 | |||
1049 | if (0 != memcmp (&coin_ev_check, | ||
1050 | &commit_coin.coin_ev, | ||
1051 | sizeof (struct TALER_RSA_BlindedSignaturePurpose))) | ||
1052 | { | ||
1053 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "blind envelope does not match for kappa=%d, old=%d\n", | ||
1054 | (int) (i+off), (int) j); | ||
1055 | // FIXME: return error code! | ||
1056 | return MHD_NO; | ||
1057 | } | ||
1058 | } | ||
1059 | } | ||
1060 | |||
1061 | |||
1062 | if (GNUNET_OK != TALER_MINT_DB_transaction (db_conn)) | ||
1063 | { | ||
1064 | GNUNET_break (0); | ||
1065 | // FIXME: return error code! | ||
1066 | return MHD_NO; | ||
1067 | } | ||
1068 | |||
1069 | for (j = 0; j < refresh_session.num_newcoins; j++) | ||
1070 | { | ||
1071 | struct RefreshCommitCoin commit_coin; | ||
1072 | struct TALER_RSA_PublicKeyBinaryEncoded denom_pub; | ||
1073 | struct TALER_MINT_DenomKeyIssuePriv *dki; | ||
1074 | struct TALER_RSA_Signature ev_sig; | ||
1075 | |||
1076 | res = TALER_MINT_DB_get_refresh_commit_coin (db_conn, | ||
1077 | refresh_session_pub, | ||
1078 | refresh_session.noreveal_index % refresh_session.kappa, | ||
1079 | j, | ||
1080 | &commit_coin); | ||
1081 | if (GNUNET_OK != res) | ||
1082 | { | ||
1083 | GNUNET_break (0); | ||
1084 | // FIXME: return error code! | ||
1085 | return MHD_NO; | ||
1086 | } | ||
1087 | res = TALER_MINT_DB_get_refresh_order (db_conn, j, refresh_session_pub, &denom_pub); | ||
1088 | if (GNUNET_OK != res) | ||
1089 | { | ||
1090 | GNUNET_break (0); | ||
1091 | // FIXME: return error code! | ||
1092 | return MHD_NO; | ||
1093 | } | ||
1094 | |||
1095 | |||
1096 | key_state = TALER_MINT_key_state_acquire (); | ||
1097 | dki = TALER_MINT_get_denom_key (key_state, &denom_pub); | ||
1098 | TALER_MINT_key_state_release (key_state); | ||
1099 | if (NULL == dki) | ||
1100 | { | ||
1101 | GNUNET_break (0); | ||
1102 | // FIXME: return error code! | ||
1103 | return MHD_NO; | ||
1104 | } | ||
1105 | if (GNUNET_OK != | ||
1106 | TALER_RSA_sign (dki->denom_priv, | ||
1107 | &commit_coin.coin_ev, | ||
1108 | sizeof (struct TALER_RSA_BlindedSignaturePurpose), | ||
1109 | &ev_sig)) | ||
1110 | { | ||
1111 | GNUNET_break (0); | ||
1112 | // FIXME: return error code! | ||
1113 | return MHD_NO; | ||
1114 | } | ||
1115 | |||
1116 | res = TALER_MINT_DB_insert_refresh_collectable (db_conn, | ||
1117 | j, | ||
1118 | refresh_session_pub, | ||
1119 | &ev_sig); | ||
1120 | if (GNUNET_OK != res) | ||
1121 | { | ||
1122 | GNUNET_break (0); | ||
1123 | // FIXME: return error code! | ||
1124 | return MHD_NO; | ||
1125 | } | ||
1126 | } | ||
1127 | /* mark that reveal was successful */ | ||
1128 | |||
1129 | res = TALER_MINT_DB_set_reveal_ok (db_conn, refresh_session_pub); | ||
1130 | if (GNUNET_OK != res) | ||
1131 | { | ||
1132 | GNUNET_break (0); | ||
1133 | // FIXME: return error code! | ||
1134 | return MHD_NO; | ||
1135 | } | ||
1136 | |||
1137 | if (GNUNET_OK != TALER_MINT_DB_commit (db_conn)) | ||
1138 | { | ||
1139 | GNUNET_break (0); | ||
1140 | return MHD_NO; | ||
1141 | } | ||
1142 | |||
1143 | return helper_refresh_reveal_send_response (connection, db_conn, refresh_session_pub); | ||
1144 | } | ||
808 | 1145 | ||
809 | 1146 | ||
810 | 1147 | ||