Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-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_withdraw.c
19 : * @brief Implementation of /reserves/$RESERVE_PUB/withdraw requests with blinding/unblinding
20 : * @author Christian Grothoff
21 : */
22 : #include "platform.h"
23 : #include <jansson.h>
24 : #include <microhttpd.h> /* just for HTTP status codes */
25 : #include <gnunet/gnunet_util_lib.h>
26 : #include <gnunet/gnunet_json_lib.h>
27 : #include <gnunet/gnunet_curl_lib.h>
28 : #include "taler_exchange_service.h"
29 : #include "taler_json_lib.h"
30 : #include "exchange_api_handle.h"
31 : #include "taler_signatures.h"
32 : #include "exchange_api_curl_defaults.h"
33 :
34 :
35 : /**
36 : * @brief A Withdraw Handle
37 : */
38 : struct TALER_EXCHANGE_WithdrawHandle
39 : {
40 :
41 : /**
42 : * The connection to exchange this request handle will use
43 : */
44 : struct TALER_EXCHANGE_Handle *exchange;
45 :
46 : /**
47 : * Handle for the actual (internal) withdraw operation.
48 : */
49 : struct TALER_EXCHANGE_Withdraw2Handle *wh2;
50 :
51 : /**
52 : * Function to call with the result.
53 : */
54 : TALER_EXCHANGE_WithdrawCallback cb;
55 :
56 : /**
57 : * Closure for @a cb.
58 : */
59 : void *cb_cls;
60 :
61 : /**
62 : * Reserve private key.
63 : */
64 : const struct TALER_ReservePrivateKeyP *reserve_priv;
65 :
66 : /**
67 : * Seed of the planchet.
68 : */
69 : struct TALER_PlanchetMasterSecretP ps;
70 :
71 : /**
72 : * blinding secret
73 : */
74 : union TALER_DenominationBlindingKeyP bks;
75 :
76 : /**
77 : * Private key of the coin we are withdrawing.
78 : */
79 : struct TALER_CoinSpendPrivateKeyP priv;
80 :
81 : /**
82 : * Details of the planchet.
83 : */
84 : struct TALER_PlanchetDetail pd;
85 :
86 : /**
87 : * Values of the @cipher selected
88 : */
89 : struct TALER_ExchangeWithdrawValues alg_values;
90 :
91 : /**
92 : * Hash of the age commitment for this coin, if applicable. Maybe NULL
93 : */
94 : const struct TALER_AgeCommitmentHash *ach;
95 :
96 : /**
97 : * Denomination key we are withdrawing.
98 : */
99 : struct TALER_EXCHANGE_DenomPublicKey pk;
100 :
101 : /**
102 : * Hash of the public key of the coin we are signing.
103 : */
104 : struct TALER_CoinPubHashP c_hash;
105 :
106 : /**
107 : * Handler for the CS R request (only used for TALER_DENOMINATION_CS denominations)
108 : */
109 : struct TALER_EXCHANGE_CsRWithdrawHandle *csrh;
110 :
111 : };
112 :
113 :
114 : /**
115 : * Function called when we're done processing the
116 : * HTTP /reserves/$RESERVE_PUB/withdraw request.
117 : *
118 : * @param cls the `struct TALER_EXCHANGE_WithdrawHandle`
119 : * @param hr HTTP response data
120 : * @param blind_sig blind signature over the coin, NULL on error
121 : */
122 : static void
123 0 : handle_reserve_withdraw_finished (
124 : void *cls,
125 : const struct TALER_EXCHANGE_HttpResponse *hr,
126 : const struct TALER_BlindedDenominationSignature *blind_sig)
127 : {
128 0 : struct TALER_EXCHANGE_WithdrawHandle *wh = cls;
129 0 : struct TALER_EXCHANGE_WithdrawResponse wr = {
130 : .hr = *hr
131 : };
132 :
133 0 : wh->wh2 = NULL;
134 0 : switch (hr->http_status)
135 : {
136 0 : case MHD_HTTP_OK:
137 : {
138 : struct TALER_FreshCoin fc;
139 :
140 0 : if (GNUNET_OK !=
141 0 : TALER_planchet_to_coin (&wh->pk.key,
142 : blind_sig,
143 0 : &wh->bks,
144 0 : &wh->priv,
145 : wh->ach,
146 0 : &wh->c_hash,
147 0 : &wh->alg_values,
148 : &fc))
149 : {
150 0 : wr.hr.http_status = 0;
151 0 : wr.hr.ec = TALER_EC_EXCHANGE_WITHDRAW_UNBLIND_FAILURE;
152 0 : break;
153 : }
154 0 : wr.details.success.coin_priv = wh->priv;
155 0 : wr.details.success.bks = wh->bks;
156 0 : wr.details.success.sig = fc.sig;
157 0 : wr.details.success.exchange_vals = wh->alg_values;
158 0 : break;
159 : }
160 0 : case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
161 : {
162 : struct GNUNET_JSON_Specification spec[] = {
163 0 : GNUNET_JSON_spec_fixed_auto (
164 : "h_payto",
165 : &wr.details.unavailable_for_legal_reasons.h_payto),
166 0 : GNUNET_JSON_spec_uint64 (
167 : "requirement_row",
168 : &wr.details.unavailable_for_legal_reasons.requirement_row),
169 0 : GNUNET_JSON_spec_end ()
170 : };
171 :
172 0 : if (GNUNET_OK !=
173 0 : GNUNET_JSON_parse (hr->reply,
174 : spec,
175 : NULL, NULL))
176 : {
177 0 : GNUNET_break_op (0);
178 0 : wr.hr.http_status = 0;
179 0 : wr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
180 0 : break;
181 : }
182 : }
183 0 : break;
184 0 : default:
185 0 : break;
186 : }
187 0 : wh->cb (wh->cb_cls,
188 : &wr);
189 0 : if (MHD_HTTP_OK == hr->http_status)
190 0 : TALER_denom_sig_free (&wr.details.success.sig);
191 0 : TALER_EXCHANGE_withdraw_cancel (wh);
192 0 : }
193 :
194 :
195 : /**
196 : * Function called when stage 1 of CS withdraw is finished (request r_pub's)
197 : *
198 : * @param cls the `struct TALER_EXCHANGE_WithdrawHandle`
199 : * @param csrr replies from the /csr-withdraw request
200 : */
201 : static void
202 0 : withdraw_cs_stage_two_callback (
203 : void *cls,
204 : const struct TALER_EXCHANGE_CsRWithdrawResponse *csrr)
205 : {
206 0 : struct TALER_EXCHANGE_WithdrawHandle *wh = cls;
207 0 : struct TALER_EXCHANGE_WithdrawResponse wr = {
208 : .hr = csrr->hr
209 : };
210 :
211 0 : wh->csrh = NULL;
212 0 : GNUNET_assert (TALER_DENOMINATION_CS == wh->pk.key.cipher);
213 0 : switch (csrr->hr.http_status)
214 : {
215 0 : case MHD_HTTP_OK:
216 0 : wh->alg_values = csrr->details.success.alg_values;
217 0 : TALER_planchet_setup_coin_priv (&wh->ps,
218 0 : &wh->alg_values,
219 : &wh->priv);
220 0 : TALER_planchet_blinding_secret_create (&wh->ps,
221 0 : &wh->alg_values,
222 : &wh->bks);
223 : /* This initializes the 2nd half of the
224 : wh->pd.blinded_planchet! */
225 0 : if (GNUNET_OK !=
226 0 : TALER_planchet_prepare (&wh->pk.key,
227 0 : &wh->alg_values,
228 0 : &wh->bks,
229 0 : &wh->priv,
230 : wh->ach,
231 : &wh->c_hash,
232 : &wh->pd))
233 : {
234 0 : GNUNET_break (0);
235 0 : GNUNET_free (wh);
236 : }
237 0 : wh->wh2 = TALER_EXCHANGE_withdraw2 (wh->exchange,
238 0 : &wh->pd,
239 : wh->reserve_priv,
240 : &handle_reserve_withdraw_finished,
241 : wh);
242 0 : return;
243 0 : default:
244 0 : break;
245 : }
246 0 : wh->cb (wh->cb_cls,
247 : &wr);
248 0 : TALER_EXCHANGE_withdraw_cancel (wh);
249 : }
250 :
251 :
252 : struct TALER_EXCHANGE_WithdrawHandle *
253 0 : TALER_EXCHANGE_withdraw (
254 : struct TALER_EXCHANGE_Handle *exchange,
255 : const struct TALER_ReservePrivateKeyP *reserve_priv,
256 : const struct TALER_EXCHANGE_WithdrawCoinInput *wci,
257 : TALER_EXCHANGE_WithdrawCallback res_cb,
258 : void *res_cb_cls)
259 : {
260 : struct TALER_EXCHANGE_WithdrawHandle *wh;
261 :
262 0 : wh = GNUNET_new (struct TALER_EXCHANGE_WithdrawHandle);
263 0 : wh->exchange = exchange;
264 0 : wh->cb = res_cb;
265 0 : wh->cb_cls = res_cb_cls;
266 0 : wh->reserve_priv = reserve_priv;
267 0 : wh->ps = *wci->ps;
268 0 : wh->ach = wci->ach;
269 0 : wh->pk = *wci->pk;
270 0 : TALER_denom_pub_deep_copy (&wh->pk.key,
271 0 : &wci->pk->key);
272 :
273 0 : switch (wci->pk->key.cipher)
274 : {
275 0 : case TALER_DENOMINATION_RSA:
276 : {
277 0 : wh->alg_values.cipher = TALER_DENOMINATION_RSA;
278 0 : TALER_planchet_setup_coin_priv (&wh->ps,
279 0 : &wh->alg_values,
280 : &wh->priv);
281 0 : TALER_planchet_blinding_secret_create (&wh->ps,
282 0 : &wh->alg_values,
283 : &wh->bks);
284 0 : if (GNUNET_OK !=
285 0 : TALER_planchet_prepare (&wh->pk.key,
286 0 : &wh->alg_values,
287 0 : &wh->bks,
288 0 : &wh->priv,
289 : wh->ach,
290 : &wh->c_hash,
291 : &wh->pd))
292 : {
293 0 : GNUNET_break (0);
294 0 : GNUNET_free (wh);
295 0 : return NULL;
296 : }
297 0 : wh->wh2 = TALER_EXCHANGE_withdraw2 (exchange,
298 0 : &wh->pd,
299 : wh->reserve_priv,
300 : &handle_reserve_withdraw_finished,
301 : wh);
302 0 : break;
303 : }
304 0 : case TALER_DENOMINATION_CS:
305 : {
306 0 : TALER_cs_withdraw_nonce_derive (
307 0 : &wh->ps,
308 : &wh->pd.blinded_planchet.details.cs_blinded_planchet.nonce);
309 : /* Note that we only initialize the first half
310 : of the blinded_planchet here; the other part
311 : will be done after the /csr-withdraw request! */
312 0 : wh->pd.blinded_planchet.cipher = TALER_DENOMINATION_CS;
313 0 : wh->csrh = TALER_EXCHANGE_csr_withdraw (
314 : exchange,
315 0 : &wh->pk,
316 0 : &wh->pd.blinded_planchet.details.cs_blinded_planchet.nonce,
317 : &withdraw_cs_stage_two_callback,
318 : wh);
319 0 : break;
320 : }
321 0 : default:
322 0 : GNUNET_break (0);
323 0 : GNUNET_free (wh);
324 0 : return NULL;
325 : }
326 0 : return wh;
327 : }
328 :
329 :
330 : void
331 0 : TALER_EXCHANGE_withdraw_cancel (struct TALER_EXCHANGE_WithdrawHandle *wh)
332 : {
333 0 : TALER_blinded_planchet_free (&wh->pd.blinded_planchet);
334 0 : if (NULL != wh->csrh)
335 : {
336 0 : TALER_EXCHANGE_csr_withdraw_cancel (wh->csrh);
337 0 : wh->csrh = NULL;
338 : }
339 0 : if (NULL != wh->wh2)
340 : {
341 0 : TALER_EXCHANGE_withdraw2_cancel (wh->wh2);
342 0 : wh->wh2 = NULL;
343 : }
344 0 : TALER_denom_pub_free (&wh->pk.key);
345 0 : GNUNET_free (wh);
346 0 : }
|