exchange_api_get-management-keys.c (13349B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2015-2026 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_get-management-keys.c 19 * @brief functions to obtain future online keys of the exchange 20 * @author Christian Grothoff 21 */ 22 #include "taler/taler_json_lib.h" 23 #include <gnunet/gnunet_curl_lib.h> 24 #include <microhttpd.h> 25 #include "taler/exchange/get-management-keys.h" 26 #include "exchange_api_curl_defaults.h" 27 #include "taler/taler_signatures.h" 28 #include "taler/taler_curl_lib.h" 29 #include "taler/taler_util.h" 30 31 /** 32 * Set to 1 for extra debug logging. 33 */ 34 #define DEBUG 0 35 36 37 /** 38 * @brief Handle for a GET /management/keys request. 39 */ 40 struct TALER_EXCHANGE_GetManagementKeysHandle 41 { 42 43 /** 44 * The base URL for this request. 45 */ 46 char *base_url; 47 48 /** 49 * The full URL for this request, set during _start. 50 */ 51 char *url; 52 53 /** 54 * Handle for the request. 55 */ 56 struct GNUNET_CURL_Job *job; 57 58 /** 59 * Function to call with the result. 60 */ 61 TALER_EXCHANGE_GetManagementKeysCallback cb; 62 63 /** 64 * Closure for @a cb. 65 */ 66 TALER_EXCHANGE_GET_MANAGEMENT_KEYS_RESULT_CLOSURE *cb_cls; 67 68 /** 69 * Reference to the execution context. 70 */ 71 struct GNUNET_CURL_Context *ctx; 72 73 }; 74 75 76 /** 77 * Handle the case that the response was of type #MHD_HTTP_OK. 78 * 79 * @param[in,out] gmkh request handle 80 * @param response the response 81 * @return #GNUNET_OK if the response was well-formed 82 */ 83 static enum GNUNET_GenericReturnValue 84 handle_ok (struct TALER_EXCHANGE_GetManagementKeysHandle *gmkh, 85 const json_t *response) 86 { 87 struct TALER_EXCHANGE_GetManagementKeysResponse gkr = { 88 .hr.http_status = MHD_HTTP_OK, 89 .hr.reply = response, 90 }; 91 struct TALER_EXCHANGE_FutureKeys *fk 92 = &gkr.details.ok.keys; 93 const json_t *sk; 94 const json_t *dk; 95 bool ok; 96 struct GNUNET_JSON_Specification spec[] = { 97 GNUNET_JSON_spec_array_const ("future_denoms", 98 &dk), 99 GNUNET_JSON_spec_array_const ("future_signkeys", 100 &sk), 101 GNUNET_JSON_spec_fixed_auto ("master_pub", 102 &fk->master_pub), 103 GNUNET_JSON_spec_fixed_auto ("denom_secmod_public_key", 104 &fk->denom_secmod_public_key), 105 GNUNET_JSON_spec_fixed_auto ("denom_secmod_cs_public_key", 106 &fk->denom_secmod_cs_public_key), 107 GNUNET_JSON_spec_fixed_auto ("signkey_secmod_public_key", 108 &fk->signkey_secmod_public_key), 109 GNUNET_JSON_spec_end () 110 }; 111 112 if (GNUNET_OK != 113 GNUNET_JSON_parse (response, 114 spec, 115 NULL, NULL)) 116 { 117 GNUNET_break_op (0); 118 return GNUNET_SYSERR; 119 } 120 fk->num_sign_keys = json_array_size (sk); 121 fk->num_denom_keys = json_array_size (dk); 122 fk->sign_keys = GNUNET_new_array ( 123 fk->num_sign_keys, 124 struct TALER_EXCHANGE_FutureSigningPublicKey); 125 fk->denom_keys = GNUNET_new_array ( 126 fk->num_denom_keys, 127 struct TALER_EXCHANGE_FutureDenomPublicKey); 128 ok = true; 129 for (unsigned int i = 0; i < fk->num_sign_keys; i++) 130 { 131 json_t *j = json_array_get (sk, 132 i); 133 struct TALER_EXCHANGE_FutureSigningPublicKey *sign_key 134 = &fk->sign_keys[i]; 135 struct GNUNET_JSON_Specification ispec[] = { 136 GNUNET_JSON_spec_fixed_auto ("key", 137 &sign_key->key), 138 GNUNET_JSON_spec_fixed_auto ("signkey_secmod_sig", 139 &sign_key->signkey_secmod_sig), 140 GNUNET_JSON_spec_timestamp ("stamp_start", 141 &sign_key->valid_from), 142 GNUNET_JSON_spec_timestamp ("stamp_expire", 143 &sign_key->valid_until), 144 GNUNET_JSON_spec_timestamp ("stamp_end", 145 &sign_key->valid_legal), 146 GNUNET_JSON_spec_end () 147 }; 148 149 if (GNUNET_OK != 150 GNUNET_JSON_parse (j, 151 ispec, 152 NULL, NULL)) 153 { 154 GNUNET_break_op (0); 155 ok = false; 156 break; 157 } 158 { 159 struct GNUNET_TIME_Relative duration 160 = GNUNET_TIME_absolute_get_difference (sign_key->valid_from.abs_time, 161 sign_key->valid_until.abs_time); 162 163 if (GNUNET_OK != 164 TALER_exchange_secmod_eddsa_verify ( 165 &sign_key->key, 166 sign_key->valid_from, 167 duration, 168 &fk->signkey_secmod_public_key, 169 &sign_key->signkey_secmod_sig)) 170 { 171 GNUNET_break_op (0); 172 ok = false; 173 break; 174 } 175 } 176 } 177 for (unsigned int i = 0; i < fk->num_denom_keys; i++) 178 { 179 json_t *j = json_array_get (dk, 180 i); 181 struct TALER_EXCHANGE_FutureDenomPublicKey *denom_key 182 = &fk->denom_keys[i]; 183 const char *section_name; 184 struct GNUNET_JSON_Specification ispec[] = { 185 TALER_JSON_spec_amount_any ("value", 186 &denom_key->value), 187 GNUNET_JSON_spec_timestamp ("stamp_start", 188 &denom_key->valid_from), 189 GNUNET_JSON_spec_timestamp ("stamp_expire_withdraw", 190 &denom_key->withdraw_valid_until), 191 GNUNET_JSON_spec_timestamp ("stamp_expire_deposit", 192 &denom_key->expire_deposit), 193 GNUNET_JSON_spec_timestamp ("stamp_expire_legal", 194 &denom_key->expire_legal), 195 TALER_JSON_spec_denom_pub ("denom_pub", 196 &denom_key->key), 197 TALER_JSON_spec_amount_any ("fee_withdraw", 198 &denom_key->fee_withdraw), 199 TALER_JSON_spec_amount_any ("fee_deposit", 200 &denom_key->fee_deposit), 201 TALER_JSON_spec_amount_any ("fee_refresh", 202 &denom_key->fee_refresh), 203 TALER_JSON_spec_amount_any ("fee_refund", 204 &denom_key->fee_refund), 205 GNUNET_JSON_spec_fixed_auto ("denom_secmod_sig", 206 &denom_key->denom_secmod_sig), 207 GNUNET_JSON_spec_string ("section_name", 208 §ion_name), 209 GNUNET_JSON_spec_end () 210 }; 211 212 if (GNUNET_OK != 213 GNUNET_JSON_parse (j, 214 ispec, 215 NULL, NULL)) 216 { 217 GNUNET_break_op (0); 218 #if DEBUG 219 json_dumpf (j, 220 stderr, 221 JSON_INDENT (2)); 222 #endif 223 ok = false; 224 break; 225 } 226 227 { 228 struct TALER_DenominationHashP h_denom_pub; 229 struct GNUNET_TIME_Relative duration 230 = GNUNET_TIME_absolute_get_difference ( 231 denom_key->valid_from.abs_time, 232 denom_key->withdraw_valid_until.abs_time); 233 234 TALER_denom_pub_hash (&denom_key->key, 235 &h_denom_pub); 236 switch (denom_key->key.bsign_pub_key->cipher) 237 { 238 case GNUNET_CRYPTO_BSA_RSA: 239 { 240 struct TALER_RsaPubHashP h_rsa; 241 242 TALER_rsa_pub_hash ( 243 denom_key->key.bsign_pub_key->details.rsa_public_key, 244 &h_rsa); 245 if (GNUNET_OK != 246 TALER_exchange_secmod_rsa_verify (&h_rsa, 247 section_name, 248 denom_key->valid_from, 249 duration, 250 &fk->denom_secmod_public_key, 251 &denom_key->denom_secmod_sig)) 252 { 253 GNUNET_break_op (0); 254 ok = false; 255 break; 256 } 257 } 258 break; 259 case GNUNET_CRYPTO_BSA_CS: 260 { 261 struct TALER_CsPubHashP h_cs; 262 263 TALER_cs_pub_hash ( 264 &denom_key->key.bsign_pub_key->details.cs_public_key, 265 &h_cs); 266 if (GNUNET_OK != 267 TALER_exchange_secmod_cs_verify (&h_cs, 268 section_name, 269 denom_key->valid_from, 270 duration, 271 &fk->denom_secmod_cs_public_key, 272 &denom_key->denom_secmod_sig)) 273 { 274 GNUNET_break_op (0); 275 ok = false; 276 break; 277 } 278 } 279 break; 280 default: 281 GNUNET_break_op (0); 282 ok = false; 283 break; 284 } 285 } 286 if (! ok) 287 break; 288 } 289 if (ok) 290 { 291 gmkh->cb (gmkh->cb_cls, 292 &gkr); 293 } 294 for (unsigned int i = 0; i < fk->num_denom_keys; i++) 295 TALER_denom_pub_free (&fk->denom_keys[i].key); 296 GNUNET_free (fk->sign_keys); 297 GNUNET_free (fk->denom_keys); 298 return (ok) ? GNUNET_OK : GNUNET_SYSERR; 299 } 300 301 302 /** 303 * Function called when we're done processing the 304 * HTTP GET /management/keys request. 305 * 306 * @param cls the `struct TALER_EXCHANGE_GetManagementKeysHandle` 307 * @param response_code HTTP response code, 0 on error 308 * @param response response body, NULL if not in JSON 309 */ 310 static void 311 handle_get_keys_finished (void *cls, 312 long response_code, 313 const void *response) 314 { 315 struct TALER_EXCHANGE_GetManagementKeysHandle *gmkh = cls; 316 const json_t *json = response; 317 struct TALER_EXCHANGE_GetManagementKeysResponse gkr = { 318 .hr.http_status = (unsigned int) response_code, 319 .hr.reply = json 320 }; 321 322 gmkh->job = NULL; 323 switch (response_code) 324 { 325 case MHD_HTTP_OK: 326 if (GNUNET_OK == 327 handle_ok (gmkh, 328 response)) 329 { 330 gmkh->cb = NULL; 331 } 332 else 333 { 334 response_code = 0; 335 } 336 break; 337 case MHD_HTTP_NOT_FOUND: 338 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 339 "Server did not find handler at `%s'. Did you configure the correct exchange base URL?\n", 340 gmkh->url); 341 if (NULL != json) 342 { 343 gkr.hr.ec = TALER_JSON_get_error_code (json); 344 gkr.hr.hint = TALER_JSON_get_error_hint (json); 345 } 346 else 347 { 348 gkr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 349 gkr.hr.hint = TALER_ErrorCode_get_hint (gkr.hr.ec); 350 } 351 break; 352 default: 353 /* unexpected response code */ 354 if (NULL != json) 355 { 356 gkr.hr.ec = TALER_JSON_get_error_code (json); 357 gkr.hr.hint = TALER_JSON_get_error_hint (json); 358 } 359 else 360 { 361 gkr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 362 gkr.hr.hint = TALER_ErrorCode_get_hint (gkr.hr.ec); 363 } 364 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 365 "Unexpected response code %u/%d for exchange management get keys\n", 366 (unsigned int) response_code, 367 (int) gkr.hr.ec); 368 break; 369 } 370 if (NULL != gmkh->cb) 371 { 372 gmkh->cb (gmkh->cb_cls, 373 &gkr); 374 gmkh->cb = NULL; 375 } 376 TALER_EXCHANGE_get_management_keys_cancel (gmkh); 377 } 378 379 380 struct TALER_EXCHANGE_GetManagementKeysHandle * 381 TALER_EXCHANGE_get_management_keys_create ( 382 struct GNUNET_CURL_Context *ctx, 383 const char *url) 384 { 385 struct TALER_EXCHANGE_GetManagementKeysHandle *gmkh; 386 387 gmkh = GNUNET_new (struct TALER_EXCHANGE_GetManagementKeysHandle); 388 gmkh->ctx = ctx; 389 gmkh->base_url = GNUNET_strdup (url); 390 return gmkh; 391 } 392 393 394 enum TALER_ErrorCode 395 TALER_EXCHANGE_get_management_keys_start ( 396 struct TALER_EXCHANGE_GetManagementKeysHandle *gmkh, 397 TALER_EXCHANGE_GetManagementKeysCallback cb, 398 TALER_EXCHANGE_GET_MANAGEMENT_KEYS_RESULT_CLOSURE *cb_cls) 399 { 400 CURL *eh; 401 402 gmkh->cb = cb; 403 gmkh->cb_cls = cb_cls; 404 gmkh->url = TALER_url_join (gmkh->base_url, 405 "management/keys", 406 NULL); 407 if (NULL == gmkh->url) 408 { 409 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 410 "Could not construct request URL.\n"); 411 return TALER_EC_GENERIC_CONFIGURATION_INVALID; 412 } 413 eh = TALER_EXCHANGE_curl_easy_get_ (gmkh->url); 414 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 415 "Requesting URL '%s'\n", 416 gmkh->url); 417 gmkh->job = GNUNET_CURL_job_add (gmkh->ctx, 418 eh, 419 &handle_get_keys_finished, 420 gmkh); 421 if (NULL == gmkh->job) 422 { 423 GNUNET_free (gmkh->url); 424 gmkh->url = NULL; 425 return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE; 426 } 427 return TALER_EC_NONE; 428 } 429 430 431 void 432 TALER_EXCHANGE_get_management_keys_cancel ( 433 struct TALER_EXCHANGE_GetManagementKeysHandle *gmkh) 434 { 435 if (NULL != gmkh->job) 436 { 437 GNUNET_CURL_job_cancel (gmkh->job); 438 gmkh->job = NULL; 439 } 440 GNUNET_free (gmkh->url); 441 GNUNET_free (gmkh->base_url); 442 GNUNET_free (gmkh); 443 } 444 445 446 /* end of exchange_api_get-management-keys.c */