exchange_api_common.h (14568B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2015-2022 Taler Systems SA 4 5 TALER 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 TALER 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 TALER; see the file COPYING. If not, see 15 <http://www.gnu.org/licenses/> 16 */ 17 /** 18 * @file lib/exchange_api_common.h 19 * @brief common functions for the exchange API 20 * @author Christian Grothoff 21 */ 22 #ifndef EXCHANGE_API_COMMON_H 23 #define EXCHANGE_API_COMMON_H 24 25 #include "taler/taler_json_lib.h" 26 #include "taler/taler_exchange_service.h" /* UNNECESSARY? */ 27 28 29 /** 30 * Check proof of a purse creation conflict. 31 * 32 * @param cpurse_sig conflicting signature (must 33 * not match the signature from the proof) 34 * @param purse_pub the public key (must match 35 * the signature from the proof) 36 * @param proof the proof to check 37 * @return #GNUNET_OK if the @a proof is OK for @a purse_pub and conflicts with @a cpurse_sig 38 */ 39 enum GNUNET_GenericReturnValue 40 TALER_EXCHANGE_check_purse_create_conflict_ ( 41 const struct TALER_PurseContractSignatureP *cpurse_sig, 42 const struct TALER_PurseContractPublicKeyP *purse_pub, 43 const json_t *proof); 44 45 46 /** 47 * Check proof of a purse merge conflict. 48 * 49 * @param cmerge_sig conflicting signature (must 50 * not match the signature from the proof) 51 * @param merge_pub the public key (must match 52 * the signature from the proof) 53 * @param purse_pub the public key of the purse 54 * @param exchange_url the base URL of this exchange 55 * @param proof the proof to check 56 * @return #GNUNET_OK if the @a proof is OK for @a purse_pub and @a merge_pub and conflicts with @a cmerge_sig 57 */ 58 enum GNUNET_GenericReturnValue 59 TALER_EXCHANGE_check_purse_merge_conflict_ ( 60 const struct TALER_PurseMergeSignatureP *cmerge_sig, 61 const struct TALER_PurseMergePublicKeyP *merge_pub, 62 const struct TALER_PurseContractPublicKeyP *purse_pub, 63 const char *exchange_url, 64 const json_t *proof); 65 66 67 /** 68 * Check @a proof that claims this coin was spend 69 * differently on the same purse already. Note that 70 * the caller must still check that @a coin_pub is 71 * in the list of coins that were used, and that 72 * @a coin_sig is different from the signature the 73 * caller used. 74 * 75 * @param purse_pub the public key of the purse 76 * @param exchange_url base URL of our exchange 77 * @param proof the proof to check 78 * @param[out] h_denom_pub hash of the coin's denomination 79 * @param[out] phac age commitment hash of the coin 80 * @param[out] coin_pub set to the conflicting coin 81 * @param[out] coin_sig set to the conflicting signature 82 * @return #GNUNET_OK if the @a proof is OK for @a purse_pub and showing that @a coin_pub was spent using @a coin_sig. 83 */ 84 enum GNUNET_GenericReturnValue 85 TALER_EXCHANGE_check_purse_coin_conflict_ ( 86 const struct TALER_PurseContractPublicKeyP *purse_pub, 87 const char *exchange_url, 88 const json_t *proof, 89 struct TALER_DenominationHashP *h_denom_pub, 90 struct TALER_AgeCommitmentHashP *phac, 91 struct TALER_CoinSpendPublicKeyP *coin_pub, 92 struct TALER_CoinSpendSignatureP *coin_sig); 93 94 95 /** 96 * Check proof of a contract conflict. 97 * 98 * @param ccontract_sig conflicting signature (must 99 * not match the signature from the proof) 100 * @param purse_pub public key of the purse 101 * @param proof the proof to check 102 * @return #GNUNET_OK if the @a proof is OK for @a purse_pub and conflicts with @a ccontract_sig 103 */ 104 enum GNUNET_GenericReturnValue 105 TALER_EXCHANGE_check_purse_econtract_conflict_ ( 106 const struct TALER_PurseContractSignatureP *ccontract_sig, 107 const struct TALER_PurseContractPublicKeyP *purse_pub, 108 const json_t *proof); 109 110 111 /** 112 * Parse a #TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY 113 * response. On success, @a cdc must be released with 114 * #TALER_EXCHANGE_free_coin_denomination_conflict_(). 115 * 116 * @param proof the response body to parse 117 * @param[out] cdc set to the parsed details, @e verified is left false 118 * @return #GNUNET_OK on success, #GNUNET_SYSERR if @a proof is malformed 119 */ 120 enum GNUNET_GenericReturnValue 121 TALER_EXCHANGE_parse_coin_denomination_conflict_ ( 122 const json_t *proof, 123 struct TALER_EXCHANGE_CoinDenominationConflict *cdc); 124 125 126 /** 127 * Check that the parsed @a cdc proves a denomination conflict for a coin 128 * the client used with denomination @a h_denom_pub: the denomination 129 * named by the exchange must differ from @a h_denom_pub, and the 130 * signature it provides must be valid for the coin under that 131 * denomination. 132 * 133 * @param keys exchange /keys structure, used to look up the 134 * denomination named in @a cdc 135 * @param h_denom_pub hash of the denomination the client used for the coin 136 * @param[in,out] cdc the parsed conflict; @e verified is set 137 * @return #GNUNET_OK if the proof is valid and was verified, 138 * #GNUNET_NO if the proof is consistent but names a denomination 139 * that is not in @a keys, so the signature could not be checked 140 * (the proof is accepted as unverifiable), 141 * #GNUNET_SYSERR if the proof is invalid 142 */ 143 enum GNUNET_GenericReturnValue 144 TALER_EXCHANGE_check_coin_denomination_conflict_ ( 145 const struct TALER_EXCHANGE_Keys *keys, 146 const struct TALER_DenominationHashP *h_denom_pub, 147 struct TALER_EXCHANGE_CoinDenominationConflict *cdc); 148 149 150 /** 151 * Release the memory held by @a cdc. 152 * 153 * @param[in] cdc parsed conflict to release 154 */ 155 void 156 TALER_EXCHANGE_free_coin_denomination_conflict_ ( 157 struct TALER_EXCHANGE_CoinDenominationConflict *cdc); 158 159 160 /** 161 * Parse a #TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_AGE_HASH 162 * response. On success, @a cac must be released with 163 * #TALER_EXCHANGE_free_coin_age_commitment_conflict_(). 164 * 165 * @param proof the response body to parse 166 * @param[out] cac set to the parsed details, @e verified is left false 167 * @return #GNUNET_OK on success, #GNUNET_SYSERR if @a proof is malformed 168 */ 169 enum GNUNET_GenericReturnValue 170 TALER_EXCHANGE_parse_coin_age_commitment_conflict_ ( 171 const json_t *proof, 172 struct TALER_EXCHANGE_CoinAgeCommitmentConflict *cac); 173 174 175 /** 176 * Check that the parsed @a cac proves an age commitment conflict for a 177 * coin the client used with denomination @a h_denom_pub and age 178 * commitment hash @a h_age_commitment: the denomination must match, 179 * the stored age commitment hash must differ, and the signature the 180 * exchange provides must be valid for the coin with the stored hash. 181 * 182 * @param keys exchange /keys structure, used to look up the denomination 183 * @param h_denom_pub hash of the denomination the client used for the coin 184 * @param h_age_commitment age commitment hash the client used for the 185 * coin, NULL if none 186 * @param[in,out] cac the parsed conflict; @e verified is set 187 * @return #GNUNET_OK if the proof is valid and was verified, 188 * #GNUNET_NO if the proof is consistent but the denomination is 189 * not in @a keys, so the signature could not be checked 190 * (the proof is accepted as unverifiable), 191 * #GNUNET_SYSERR if the proof is invalid 192 */ 193 enum GNUNET_GenericReturnValue 194 TALER_EXCHANGE_check_coin_age_commitment_conflict_ ( 195 const struct TALER_EXCHANGE_Keys *keys, 196 const struct TALER_DenominationHashP *h_denom_pub, 197 const struct TALER_AgeCommitmentHashP *h_age_commitment, 198 struct TALER_EXCHANGE_CoinAgeCommitmentConflict *cac); 199 200 201 /** 202 * Release the memory held by @a cac. 203 * 204 * @param[in] cac parsed conflict to release 205 */ 206 void 207 TALER_EXCHANGE_free_coin_age_commitment_conflict_ ( 208 struct TALER_EXCHANGE_CoinAgeCommitmentConflict *cac); 209 210 211 /** 212 * Function called by #TALER_EXCHANGE_check_coin_conflict_() to find 213 * out how the client used the coin @a coin_pub in the request. 214 * 215 * @param cls closure 216 * @param coin_pub public key of the coin named in the conflict reply 217 * @param[out] h_denom_pub set to the hash of the denomination the 218 * client used for the coin 219 * @param[out] h_age_commitment set to the age commitment hash the 220 * client used for the coin, or NULL if none 221 * @return #GNUNET_OK if the coin was found and the outputs are set, 222 * #GNUNET_NO if the request did not contain @a coin_pub 223 */ 224 typedef enum GNUNET_GenericReturnValue 225 (*TALER_EXCHANGE_CoinLookupCallback_)( 226 void *cls, 227 const struct TALER_CoinSpendPublicKeyP *coin_pub, 228 const struct TALER_DenominationHashP **h_denom_pub, 229 const struct TALER_AgeCommitmentHashP **h_age_commitment); 230 231 232 /** 233 * Handle a 409 reply with error code @a ec, which must be 234 * #TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY or 235 * #TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_AGE_HASH: parse @a proof 236 * into @a cc, find the coin it names via @a lookup, and check the 237 * proof against what the client used for that coin (see 238 * #TALER_EXCHANGE_check_coin_denomination_conflict_() and 239 * #TALER_EXCHANGE_check_coin_age_commitment_conflict_()). 240 * 241 * On success, @a cc must be released with 242 * #TALER_EXCHANGE_free_coin_conflict_() once the application was 243 * informed. On failure, @a cc is already released and its 244 * @e ec is #TALER_EC_NONE. 245 * 246 * @param keys exchange /keys structure 247 * @param ec error code of the reply 248 * @param proof body of the reply 249 * @param lookup function to find the coin in the request 250 * @param lookup_cls closure for @a lookup 251 * @param[out] cc set to the parsed and checked reply, with @e ec set to @a ec 252 * @return #GNUNET_OK if the proof is valid (verified, or accepted as 253 * unverifiable), #GNUNET_SYSERR if the reply is malformed or 254 * the proof is invalid 255 */ 256 enum GNUNET_GenericReturnValue 257 TALER_EXCHANGE_check_coin_conflict_ ( 258 const struct TALER_EXCHANGE_Keys *keys, 259 enum TALER_ErrorCode ec, 260 const json_t *proof, 261 TALER_EXCHANGE_CoinLookupCallback_ lookup, 262 void *lookup_cls, 263 struct TALER_EXCHANGE_CoinConflict *cc); 264 265 266 /** 267 * Release the memory held by @a cc, if @a hr says that the reply was 268 * a coin conflict and @a cc was filled by 269 * #TALER_EXCHANGE_check_coin_conflict_(). @a cc usually lives in a 270 * union with the details of other replies, so its own @e ec must not 271 * be trusted before @a hr was consulted. 272 * 273 * @param hr HTTP response the details belong to 274 * @param[in] cc conflict details to release; @e ec is reset 275 */ 276 void 277 TALER_EXCHANGE_free_coin_conflict_ ( 278 const struct TALER_EXCHANGE_HttpResponse *hr, 279 struct TALER_EXCHANGE_CoinConflict *cc); 280 281 282 /** 283 * Find the smallest denomination amount in @e keys. 284 * 285 * @param keys keys to search 286 * @param[out] min set to the smallest amount 287 * @return #GNUNET_SYSERR if there are no denominations in @a keys 288 */ 289 enum GNUNET_GenericReturnValue 290 TALER_EXCHANGE_get_min_denomination_ ( 291 const struct TALER_EXCHANGE_Keys *keys, 292 struct TALER_Amount *min); 293 294 295 /** 296 * Verify signature information about the deposit. 297 * 298 * @param dcd contract details 299 * @param ech hashed policy (passed to avoid recomputation) 300 * @param h_wire hashed wire details (passed to avoid recomputation) 301 * @param cdd coin-specific details 302 * @param dki denomination of the coin 303 * @return #GNUNET_OK if signatures are OK, #GNUNET_SYSERR if not 304 */ 305 enum GNUNET_GenericReturnValue 306 TALER_EXCHANGE_verify_deposit_signature_ ( 307 const struct TALER_EXCHANGE_DepositContractDetail *dcd, 308 const struct TALER_ExtensionPolicyHashP *ech, 309 const struct TALER_MerchantWireHashP *h_wire, 310 const struct TALER_EXCHANGE_CoinDepositDetail *cdd, 311 const struct TALER_EXCHANGE_DenomPublicKey *dki); 312 313 314 /** 315 * Denomination and age commitment of a coin disclosed for recoup, 316 * kept to check a conflict reply against. 317 */ 318 struct TALER_EXCHANGE_RecoupedCoinInfo_ 319 { 320 /** 321 * Hash of the denomination of the coin. 322 */ 323 struct TALER_DenominationHashP h_denom_pub; 324 325 /** 326 * Age commitment hash of the coin, if @e have_age. 327 */ 328 struct TALER_AgeCommitmentHashP h_age_commitment; 329 330 /** 331 * True if the coin has an age commitment. 332 */ 333 bool have_age; 334 }; 335 336 337 /** 338 * Build the ``coin_data`` array of a recoup request: the hash of the 339 * blinded envelope for coins that are not to be recouped, the disclosed 340 * coin with its recoup signature for the others. 341 * 342 * @param num_coins number of coins the exchange signed in the operation 343 * @param coins the coins, in the order of the operation 344 * @param blinding_seed blinding seed of the operation, NULL if there 345 * are no CS coins 346 * @param for_melt true if the operation was a melt (affects the 347 * nonce derivation and the signature purpose) 348 * @param[out] recouped_infos array of @a num_coins entries, set to the 349 * denomination and age commitment of the recouped coins, in the 350 * order of @a recouped_pubs 351 * @param[out] recouped_pubs array of @a num_coins entries, set to the 352 * public keys of the recouped coins, in order 353 * @param[out] num_recouped set to the number of recouped coins 354 * @return the JSON array, NULL on failure (no disclosed coin, or a CS 355 * coin without @a blinding_seed) 356 */ 357 json_t * 358 TALER_EXCHANGE_recoup_coin_data_ ( 359 size_t num_coins, 360 const struct TALER_EXCHANGE_RecoupCoin coins[static num_coins], 361 const struct TALER_BlindingMasterSeedP *blinding_seed, 362 bool for_melt, 363 struct TALER_CoinSpendPublicKeyP recouped_pubs[static num_coins], 364 struct TALER_EXCHANGE_RecoupedCoinInfo_ recouped_infos[static num_coins], 365 size_t *num_recouped); 366 367 368 /** 369 * Parse the ``recoups`` array of a recoup response and check it 370 * against the request: the entries must name the recouped coins in 371 * request order and their amounts must add up to @a total_amount. 372 * 373 * @param j_recoups the JSON array 374 * @param num_expected number of recouped coins in the request 375 * @param expected_pubs their public keys, in order 376 * @param total_amount total amount claimed by the response 377 * @param[out] recoups set to an array of @a num_expected entries, to 378 * be freed by the caller 379 * @param[out] h_recoups set to the hash over the entries as covered 380 * by the batch confirmation signature 381 * @return #GNUNET_OK on success 382 */ 383 enum GNUNET_GenericReturnValue 384 TALER_EXCHANGE_parse_recoups_ ( 385 const json_t *j_recoups, 386 size_t num_expected, 387 const struct TALER_CoinSpendPublicKeyP expected_pubs[static num_expected], 388 const struct TALER_Amount *total_amount, 389 struct TALER_RecoupedCoin **recoups, 390 struct GNUNET_HashCode *h_recoups); 391 392 #endif