Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2014-2023 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify
6 : it under the terms of the GNU General Public License as
7 : published by the Free Software Foundation; either version 3, or
8 : (at your option) any later version.
9 :
10 : TALER is distributed in the hope that it will be useful, but
11 : WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU General Public License for more details.
14 :
15 : You should have received a copy of the GNU General Public
16 : License along with TALER; see the file COPYING. If not, see
17 : <http://www.gnu.org/licenses/>
18 : */
19 : /**
20 : * @file testing/testing_api_cmd_revoke_sign_key.c
21 : * @brief Implement the revoke test command.
22 : * @author Christian Grothoff
23 : */
24 : #include "taler/taler_json_lib.h"
25 : #include <gnunet/gnunet_curl_lib.h>
26 : struct RevokeState;
27 : #define TALER_EXCHANGE_POST_MANAGEMENT_SIGNKEYS_REVOKE_RESULT_CLOSURE \
28 : struct RevokeState
29 : #include "taler/exchange/post-management-signkeys-EXCHANGE_PUB-revoke.h"
30 : #include "taler/taler_testing_lib.h"
31 :
32 :
33 : /**
34 : * State for a "revoke" CMD.
35 : */
36 : struct RevokeState
37 : {
38 : /**
39 : * Expected HTTP status code.
40 : */
41 : unsigned int expected_response_code;
42 :
43 : /**
44 : * Command that offers a signination to revoke.
45 : */
46 : const char *coin_reference;
47 :
48 : /**
49 : * The interpreter state.
50 : */
51 : struct TALER_TESTING_Interpreter *is;
52 :
53 : /**
54 : * Handle for the operation.
55 : */
56 : struct TALER_EXCHANGE_PostManagementSignkeysRevokeHandle *kh;
57 :
58 : /**
59 : * Should we use a bogus signature?
60 : */
61 : bool bad_sig;
62 :
63 : };
64 :
65 :
66 : /**
67 : * Function called with information about the post revocation operation result.
68 : *
69 : * @param rs closure with a `struct RevokeState *`
70 : * @param rsr response data
71 : */
72 : static void
73 4 : success_cb (
74 : struct RevokeState *rs,
75 : const struct TALER_EXCHANGE_PostManagementSignkeysRevokeResponse *rsr)
76 : {
77 4 : const struct TALER_EXCHANGE_HttpResponse *hr = &rsr->hr;
78 :
79 4 : rs->kh = NULL;
80 4 : if (rs->expected_response_code != hr->http_status)
81 : {
82 0 : TALER_TESTING_unexpected_status (rs->is,
83 : hr->http_status,
84 : rs->expected_response_code);
85 0 : return;
86 : }
87 4 : TALER_TESTING_interpreter_next (rs->is);
88 : }
89 :
90 :
91 : /**
92 : * Cleanup the state.
93 : *
94 : * @param cls closure, must be a `struct RevokeState`.
95 : * @param cmd the command which is being cleaned up.
96 : */
97 : static void
98 4 : revoke_cleanup (void *cls,
99 : const struct TALER_TESTING_Command *cmd)
100 : {
101 4 : struct RevokeState *rs = cls;
102 :
103 4 : if (NULL != rs->kh)
104 : {
105 0 : TALER_EXCHANGE_post_management_signkeys_revoke_cancel (rs->kh);
106 0 : rs->kh = NULL;
107 : }
108 4 : GNUNET_free (rs);
109 4 : }
110 :
111 :
112 : /**
113 : * Offer internal data from a "revoke" CMD to other CMDs.
114 : *
115 : * @param cls closure
116 : * @param[out] ret result (could be anything)
117 : * @param trait name of the trait
118 : * @param index index number of the object to offer.
119 : * @return #GNUNET_OK on success
120 : */
121 : static int
122 0 : revoke_traits (void *cls,
123 : const void **ret,
124 : const char *trait,
125 : unsigned int index)
126 : {
127 0 : struct RevokeState *rs = cls;
128 : struct TALER_TESTING_Trait traits[] = {
129 0 : TALER_TESTING_trait_end ()
130 : };
131 :
132 : (void) rs;
133 0 : return TALER_TESTING_get_trait (traits,
134 : ret,
135 : trait,
136 : index);
137 : }
138 :
139 :
140 : /**
141 : * Run the "revoke" command for a signing key.
142 : *
143 : * @param cls closure.
144 : * @param cmd the command to execute.
145 : * @param is the interpreter state.
146 : */
147 : static void
148 4 : revoke_run (void *cls,
149 : const struct TALER_TESTING_Command *cmd,
150 : struct TALER_TESTING_Interpreter *is)
151 : {
152 4 : struct RevokeState *rs = cls;
153 : const struct TALER_TESTING_Command *coin_cmd;
154 : const struct TALER_ExchangePublicKeyP *exchange_pub;
155 : struct TALER_MasterSignatureP master_sig;
156 : const char *exchange_url;
157 :
158 : {
159 : const struct TALER_TESTING_Command *exchange_cmd;
160 :
161 4 : exchange_cmd = TALER_TESTING_interpreter_get_command (is,
162 : "exchange");
163 4 : if (NULL == exchange_cmd)
164 : {
165 0 : GNUNET_break (0);
166 0 : TALER_TESTING_interpreter_fail (is);
167 0 : return;
168 : }
169 4 : GNUNET_assert (GNUNET_OK ==
170 : TALER_TESTING_get_trait_exchange_url (exchange_cmd,
171 : &exchange_url));
172 : }
173 4 : rs->is = is;
174 : /* Get sign pub from trait */
175 4 : coin_cmd = TALER_TESTING_interpreter_lookup_command (is,
176 : rs->coin_reference);
177 :
178 4 : if (NULL == coin_cmd)
179 : {
180 0 : GNUNET_break (0);
181 0 : TALER_TESTING_interpreter_fail (is);
182 0 : return;
183 : }
184 4 : GNUNET_assert (GNUNET_OK ==
185 : TALER_TESTING_get_trait_exchange_pub (coin_cmd,
186 : 0,
187 : &exchange_pub));
188 4 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
189 : "Trying to revoke sign '%s..'\n",
190 : TALER_B2S (exchange_pub));
191 4 : if (rs->bad_sig)
192 : {
193 2 : memset (&master_sig,
194 : 42,
195 : sizeof (master_sig));
196 : }
197 : else
198 : {
199 : const struct TALER_TESTING_Command *exchange_cmd;
200 : const struct TALER_MasterPrivateKeyP *master_priv;
201 :
202 2 : exchange_cmd = TALER_TESTING_interpreter_get_command (is,
203 : "exchange");
204 2 : if (NULL == exchange_cmd)
205 : {
206 0 : GNUNET_break (0);
207 0 : TALER_TESTING_interpreter_fail (is);
208 0 : return;
209 : }
210 2 : GNUNET_assert (GNUNET_OK ==
211 : TALER_TESTING_get_trait_master_priv (exchange_cmd,
212 : &master_priv));
213 2 : TALER_exchange_offline_signkey_revoke_sign (exchange_pub,
214 : master_priv,
215 : &master_sig);
216 : }
217 4 : rs->kh = TALER_EXCHANGE_post_management_signkeys_revoke_create (
218 : TALER_TESTING_interpreter_get_context (is),
219 : exchange_url,
220 : exchange_pub,
221 : &master_sig);
222 4 : if (NULL == rs->kh)
223 : {
224 0 : GNUNET_break (0);
225 0 : TALER_TESTING_interpreter_fail (is);
226 0 : return;
227 : }
228 4 : TALER_EXCHANGE_post_management_signkeys_revoke_start (rs->kh, &success_cb, rs)
229 : ;
230 : }
231 :
232 :
233 : struct TALER_TESTING_Command
234 4 : TALER_TESTING_cmd_revoke_sign_key (
235 : const char *label,
236 : unsigned int expected_response_code,
237 : bool bad_sig,
238 : const char *sign_ref)
239 : {
240 : struct RevokeState *rs;
241 :
242 4 : rs = GNUNET_new (struct RevokeState);
243 4 : rs->expected_response_code = expected_response_code;
244 4 : rs->coin_reference = sign_ref;
245 4 : rs->bad_sig = bad_sig;
246 : {
247 4 : struct TALER_TESTING_Command cmd = {
248 : .cls = rs,
249 : .label = label,
250 : .run = &revoke_run,
251 : .cleanup = &revoke_cleanup,
252 : .traits = &revoke_traits
253 : };
254 :
255 4 : return cmd;
256 : }
257 : }
258 :
259 :
260 : /**
261 : * State for a "check signkey revoked" CMD.
262 : */
263 : struct CheckRevokedState
264 : {
265 : /**
266 : * Command that offers the revoked signing key.
267 : */
268 : const char *signkey_ref;
269 :
270 : /**
271 : * "get exchange" command that downloaded /keys before the revocation.
272 : */
273 : const char *keys_before_ref;
274 :
275 : /**
276 : * "get exchange" command that downloaded /keys after the revocation.
277 : */
278 : const char *keys_after_ref;
279 : };
280 :
281 :
282 : /**
283 : * Obtain the /keys of the "get exchange" command @a label.
284 : *
285 : * @param is interpreter state
286 : * @param label label of the command
287 : * @return NULL on error
288 : */
289 : static const struct TALER_EXCHANGE_Keys *
290 4 : get_keys_of (struct TALER_TESTING_Interpreter *is,
291 : const char *label)
292 : {
293 : const struct TALER_TESTING_Command *cmd;
294 : struct TALER_EXCHANGE_Keys *keys;
295 :
296 4 : cmd = TALER_TESTING_interpreter_lookup_command (is,
297 : label);
298 8 : if ( (NULL == cmd) ||
299 : (GNUNET_OK !=
300 4 : TALER_TESTING_get_trait_keys (cmd,
301 : &keys)) )
302 0 : return NULL;
303 4 : return keys;
304 : }
305 :
306 :
307 : /**
308 : * Run the "check signkey revoked" command.
309 : *
310 : * @param cls a `struct CheckRevokedState`
311 : * @param cmd the command currently being executed.
312 : * @param is the interpreter state.
313 : */
314 : static void
315 2 : check_revoked_run (void *cls,
316 : const struct TALER_TESTING_Command *cmd,
317 : struct TALER_TESTING_Interpreter *is)
318 : {
319 2 : struct CheckRevokedState *crs = cls;
320 : const struct TALER_TESTING_Command *sk_cmd;
321 : const struct TALER_ExchangePublicKeyP *exchange_pub;
322 : const struct TALER_EXCHANGE_Keys *before;
323 : const struct TALER_EXCHANGE_Keys *after;
324 :
325 : (void) cmd;
326 2 : sk_cmd = TALER_TESTING_interpreter_lookup_command (is,
327 : crs->signkey_ref);
328 2 : before = get_keys_of (is,
329 : crs->keys_before_ref);
330 2 : after = get_keys_of (is,
331 : crs->keys_after_ref);
332 4 : if ( (NULL == sk_cmd) ||
333 : (GNUNET_OK !=
334 2 : TALER_TESTING_get_trait_exchange_pub (sk_cmd,
335 : 0,
336 2 : &exchange_pub)) ||
337 2 : (NULL == before) ||
338 : (NULL == after) )
339 : {
340 0 : GNUNET_break (0);
341 0 : TALER_TESTING_interpreter_fail (is);
342 0 : return;
343 : }
344 : /* The key was valid before the revocation ... */
345 2 : if (GNUNET_OK !=
346 2 : TALER_EXCHANGE_test_signing_key (before,
347 : exchange_pub))
348 : {
349 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
350 : "Signing key %s was not valid before its revocation\n",
351 : TALER_B2S (exchange_pub));
352 0 : TALER_TESTING_interpreter_fail (is);
353 0 : return;
354 : }
355 : /* ... /keys no longer lists it after the revocation ... */
356 4 : for (unsigned int i = 0; i<after->num_sign_keys; i++)
357 : {
358 2 : if (0 ==
359 2 : GNUNET_memcmp (exchange_pub,
360 : &after->sign_keys[i].key))
361 : {
362 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
363 : "/keys still lists revoked signing key %s\n",
364 : TALER_B2S (exchange_pub));
365 0 : TALER_TESTING_interpreter_fail (is);
366 0 : return;
367 : }
368 : }
369 : /* ... so the client rejects replies signed with it. */
370 2 : if (GNUNET_SYSERR !=
371 2 : TALER_EXCHANGE_test_signing_key (after,
372 : exchange_pub))
373 : {
374 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
375 : "Client still accepts revoked signing key %s\n",
376 : TALER_B2S (exchange_pub));
377 0 : TALER_TESTING_interpreter_fail (is);
378 0 : return;
379 : }
380 2 : TALER_TESTING_interpreter_next (is);
381 : }
382 :
383 :
384 : /**
385 : * Free the state of a "check signkey revoked" CMD.
386 : *
387 : * @param cls a `struct CheckRevokedState`
388 : * @param cmd the command which is being cleaned up.
389 : */
390 : static void
391 2 : check_revoked_cleanup (void *cls,
392 : const struct TALER_TESTING_Command *cmd)
393 : {
394 2 : struct CheckRevokedState *crs = cls;
395 :
396 : (void) cmd;
397 2 : GNUNET_free (crs);
398 2 : }
399 :
400 :
401 : struct TALER_TESTING_Command
402 2 : TALER_TESTING_cmd_check_signkey_revoked (
403 : const char *label,
404 : const char *signkey_ref,
405 : const char *keys_before_ref,
406 : const char *keys_after_ref)
407 : {
408 : struct CheckRevokedState *crs;
409 :
410 2 : crs = GNUNET_new (struct CheckRevokedState);
411 2 : crs->signkey_ref = signkey_ref;
412 2 : crs->keys_before_ref = keys_before_ref;
413 2 : crs->keys_after_ref = keys_after_ref;
414 : {
415 2 : struct TALER_TESTING_Command cmd = {
416 : .cls = crs,
417 : .label = label,
418 : .run = &check_revoked_run,
419 : .cleanup = &check_revoked_cleanup
420 : };
421 :
422 2 : return cmd;
423 : }
424 : }
|