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