taler-exchange-httpd_blinding-prepare.c (7383B)
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_blinding-prepare.c 21 * @brief Handle /blinding-prepare requests 22 * @author Özgür Kesim 23 */ 24 #include "taler/platform.h" 25 #include <gnunet/gnunet_util_lib.h> 26 #include <jansson.h> 27 #include "taler/taler_json_lib.h" 28 #include "taler/taler_mhd_lib.h" 29 #include "taler-exchange-httpd_blinding-prepare.h" 30 #include "taler-exchange-httpd_responses.h" 31 #include "taler-exchange-httpd_keys.h" 32 33 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_keys_denomination_cs_batch_r_pub (ksh, 162 num, 163 h_denom_pubs, 164 nonces, 165 is_melt, 166 r_pubs, 167 &err_idx); 168 switch (ec) 169 { 170 case TALER_EC_NONE: 171 break; 172 case TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN: 173 return TEH_RESPONSE_reply_unknown_denom_pub_hash ( 174 rc->connection, 175 &h_denom_pubs[err_idx]); 176 break; 177 case TALER_EC_EXCHANGE_GENERIC_INVALID_DENOMINATION_CIPHER_FOR_OPERATION: 178 return TEH_RESPONSE_reply_invalid_denom_cipher_for_operation ( 179 rc->connection, 180 &h_denom_pubs[err_idx]); 181 break; 182 case TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED: 183 return TEH_RESPONSE_reply_expired_denom_pub_hash ( 184 rc->connection, 185 &h_denom_pubs[err_idx], 186 ec, 187 "blinding-prepare"); 188 break; 189 case TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE: 190 return TEH_RESPONSE_reply_expired_denom_pub_hash ( 191 rc->connection, 192 &h_denom_pubs[err_idx], 193 ec, 194 "blinding-prepare"); 195 break; 196 default: 197 GNUNET_break (0); 198 return TALER_MHD_reply_with_ec (rc->connection, 199 ec, 200 NULL); 201 break; 202 } 203 204 /* Finally, create the response */ 205 { 206 struct TALER_BlindingPrepareResponse response = { 207 .num = num, 208 .cipher = GNUNET_CRYPTO_BSA_CS, 209 .details.cs = r_pubs, 210 }; 211 212 return TALER_MHD_REPLY_JSON_PACK ( 213 rc->connection, 214 MHD_HTTP_OK, 215 TALER_JSON_pack_blinding_prepare_response (NULL, 216 &response)); 217 } 218 } 219 } 220 } 221 222 223 /* end of taler-exchange-httpd_blinding_prepare.c */