taler-exchange-httpd_post-blinding-prepare.c (7342B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2025 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify 6 it under the terms of the GNU Affero General Public License as 7 published by the Free Software Foundation; either version 3, 8 or (at your option) any later version. 9 10 TALER is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty 12 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13 See the GNU Affero General Public License for more details. 14 15 You should have received a copy of the GNU Affero General 16 Public License along with TALER; see the file COPYING. If not, 17 see <http://www.gnu.org/licenses/> 18 */ 19 /** 20 * @file taler-exchange-httpd_post-blinding-prepare.c 21 * @brief Handle /blinding-prepare requests 22 * @author Özgür Kesim 23 */ 24 #include <gnunet/gnunet_util_lib.h> 25 #include <jansson.h> 26 #include "taler/taler_json_lib.h" 27 #include "taler/taler_mhd_lib.h" 28 #include "taler-exchange-httpd_secmod-helpers.h" 29 #include "taler-exchange-httpd_post-blinding-prepare.h" 30 #include "taler-exchange-httpd_responses.h" 31 #include "taler-exchange-httpd_get-keys.h" 32 33 enum MHD_Result 34 TEH_handler_blinding_prepare (struct TEH_RequestContext *rc, 35 const json_t *root, 36 const char *const args[]) 37 { 38 struct TALER_BlindingMasterSeedP blinding_seed; 39 const char *cipher; 40 const char *operation; 41 const json_t *j_nks; 42 size_t num; 43 bool is_melt; 44 struct GNUNET_JSON_Specification spec[] = { 45 GNUNET_JSON_spec_string ("cipher", 46 &cipher), 47 GNUNET_JSON_spec_string ("operation", 48 &operation), 49 GNUNET_JSON_spec_fixed_auto ("seed", 50 &blinding_seed), 51 GNUNET_JSON_spec_array_const ("nks", 52 &j_nks), 53 GNUNET_JSON_spec_end () 54 }; 55 56 (void) args; 57 { 58 enum GNUNET_GenericReturnValue res; 59 60 res = TALER_MHD_parse_json_data (rc->connection, 61 root, 62 spec); 63 if (GNUNET_OK != res) 64 return (GNUNET_SYSERR == res) 65 ? MHD_NO 66 : MHD_YES; 67 } 68 if (0 == strcmp (operation, 69 "melt")) 70 { 71 is_melt = true; 72 } 73 else if (0 == strcmp (operation, 74 "withdraw")) 75 { 76 is_melt = false; 77 } 78 else 79 { 80 GNUNET_break_op (0); 81 return TALER_MHD_reply_with_error (rc->connection, 82 MHD_HTTP_BAD_REQUEST, 83 TALER_EC_GENERIC_PARAMETER_MALFORMED, 84 "operation"); 85 } 86 87 num = json_array_size (j_nks); 88 if ((0 == num) || 89 (TALER_MAX_COINS < num)) 90 { 91 GNUNET_break_op (0); 92 return TALER_MHD_reply_with_error (rc->connection, 93 MHD_HTTP_BAD_REQUEST, 94 TALER_EC_EXCHANGE_GENERIC_NEW_DENOMS_ARRAY_SIZE_EXCESSIVE, 95 "nks"); 96 } 97 if (0 != strcmp (cipher, "CS")) 98 { 99 GNUNET_break_op (0); 100 return TALER_MHD_reply_with_error (rc->connection, 101 MHD_HTTP_BAD_REQUEST, 102 TALER_EC_GENERIC_PARAMETER_MALFORMED, 103 " cipher"); 104 } 105 106 { 107 uint32_t cs_indices[num]; 108 struct TALER_DenominationHashP h_denom_pubs[num]; 109 struct GNUNET_CRYPTO_CsSessionNonce nonces[num]; 110 111 for (size_t i = 0; i < num; i++) 112 { 113 enum GNUNET_GenericReturnValue res; 114 struct GNUNET_JSON_Specification nks_spec[] = { 115 GNUNET_JSON_spec_fixed_auto ("denom_pub_hash", 116 &h_denom_pubs[i]), 117 GNUNET_JSON_spec_uint32 ("coin_offset", 118 &cs_indices[i]), 119 GNUNET_JSON_spec_end () 120 }; 121 122 res = TALER_MHD_parse_json_array (rc->connection, 123 j_nks, 124 nks_spec, 125 i, 126 -1); 127 if (GNUNET_OK != res) 128 return (GNUNET_SYSERR == res) 129 ? MHD_NO 130 : MHD_YES; 131 132 if (TALER_MAX_COINS < cs_indices[i]) 133 { 134 GNUNET_break_op (0); 135 return TALER_MHD_reply_with_error (rc->connection, 136 MHD_HTTP_BAD_REQUEST, 137 TALER_EC_GENERIC_PARAMETER_MALFORMED, 138 "nks"); 139 } 140 } 141 142 TALER_cs_derive_nonces_from_seed (&blinding_seed, 143 is_melt, 144 num, 145 cs_indices, 146 nonces); 147 { 148 struct TEH_KeyStateHandle *ksh; 149 struct GNUNET_CRYPTO_CSPublicRPairP r_pubs[num]; 150 size_t err_idx; 151 enum TALER_ErrorCode ec; 152 153 ksh = TEH_keys_get_state (); 154 if (NULL == ksh) 155 return TALER_MHD_reply_with_error (rc->connection, 156 MHD_HTTP_INTERNAL_SERVER_ERROR, 157 TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING, 158 NULL); 159 160 ec = 161 TEH_SECMOD_denom_cs_batch_r_pub (num, 162 h_denom_pubs, 163 nonces, 164 is_melt, 165 r_pubs, 166 &err_idx); 167 switch (ec) 168 { 169 case TALER_EC_NONE: 170 break; 171 case TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN: 172 return TEH_RESPONSE_reply_unknown_denom_pub_hash ( 173 rc->connection, 174 &h_denom_pubs[err_idx]); 175 break; 176 case TALER_EC_EXCHANGE_GENERIC_INVALID_DENOMINATION_CIPHER_FOR_OPERATION: 177 return TEH_RESPONSE_reply_invalid_denom_cipher_for_operation ( 178 rc->connection, 179 &h_denom_pubs[err_idx]); 180 break; 181 case TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED: 182 return TEH_RESPONSE_reply_expired_denom_pub_hash ( 183 rc->connection, 184 &h_denom_pubs[err_idx], 185 ec, 186 "blinding-prepare"); 187 break; 188 case TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE: 189 return TEH_RESPONSE_reply_expired_denom_pub_hash ( 190 rc->connection, 191 &h_denom_pubs[err_idx], 192 ec, 193 "blinding-prepare"); 194 break; 195 default: 196 GNUNET_break (0); 197 return TALER_MHD_reply_with_ec (rc->connection, 198 ec, 199 NULL); 200 break; 201 } 202 203 /* Finally, create the response */ 204 { 205 struct TALER_BlindingPrepareResponse response = { 206 .num = num, 207 .cipher = GNUNET_CRYPTO_BSA_CS, 208 .details.cs = r_pubs, 209 }; 210 211 return TALER_MHD_REPLY_JSON_PACK ( 212 rc->connection, 213 MHD_HTTP_OK, 214 TALER_JSON_pack_blinding_prepare_response (NULL, 215 &response)); 216 } 217 } 218 } 219 } 220 221 222 /* end of taler-exchange-httpd_blinding_prepare.c */