testing_cmd_recover_secret.c (12253B)
1 /* 2 This file is part of Anastasis 3 Copyright (C) 2020, 2021 Anastasis SARL 4 5 Anastasis 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 Anastasis 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 Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file testing/testing_cmd_recover_secret.c 18 * @brief command to execute the anastasis recovery service 19 * @author Christian Grothoff 20 * @author Dennis Neufeld 21 * @author Dominik Meister 22 */ 23 #include "platform.h" 24 #include "anastasis_testing_lib.h" 25 #include <taler/taler_util.h> 26 #include <taler/taler_testing_lib.h> 27 28 29 /** 30 * State for a "recover secret" CMD. 31 */ 32 struct RecoverSecretState 33 { 34 /** 35 * The interpreter state. 36 */ 37 struct TALER_TESTING_Interpreter *is; 38 39 /** 40 * URL of the anastasis backend. 41 */ 42 const char *anastasis_url; 43 44 /** 45 * The /policy GET operation handle. 46 */ 47 struct ANASTASIS_Recovery *recovery; 48 49 /** 50 * Reference to download command we expect to look up. 51 */ 52 const char *download_reference; 53 54 /** 55 * Reference to core secret share we expect to look up. 56 */ 57 const char *core_secret_reference; 58 59 /** 60 * Options for how we are supposed to do the download. 61 */ 62 enum ANASTASIS_TESTING_RecoverSecretOption rsopt; 63 64 /** 65 * Identification data from the user 66 */ 67 json_t *id_data; 68 69 /** 70 * Recovery information from the lookup 71 */ 72 struct ANASTASIS_RecoveryInformation *ri; 73 74 /** 75 * Coresecret to check if decryption worked 76 */ 77 const void *core_secret; 78 79 /** 80 * Task scheduled to wait for recovery to complete. 81 */ 82 struct GNUNET_SCHEDULER_Task *recovery_task; 83 84 /** 85 * version of the recovery document 86 */ 87 unsigned int version; 88 89 /** 90 * #GNUNET_OK if the secret was recovered, #GNUNET_SYSERR if 91 * recovery failed (yielded wrong secret). 92 */ 93 int recovered; 94 }; 95 96 97 /** 98 * Callback which passes back the recovery document and its possible 99 * policies. Also passes back the version of the document for the user 100 * to check. 101 * 102 * @param cls closure for the callback 103 * @param ri recovery information struct which contains the policies 104 */ 105 static void 106 policy_lookup_cb (void *cls, 107 const struct ANASTASIS_RecoveryInformation *ri) 108 { 109 struct RecoverSecretState *rss = cls; 110 111 if (NULL == ri) 112 { 113 GNUNET_break (0); 114 TALER_TESTING_interpreter_fail (rss->is); 115 return; 116 } 117 if (0 == ri->cs_len) 118 { 119 GNUNET_break (0); 120 TALER_TESTING_interpreter_fail (rss->is); 121 return; 122 } 123 rss->ri = (struct ANASTASIS_RecoveryInformation *) ri; 124 TALER_TESTING_interpreter_next (rss->is); 125 } 126 127 128 /** 129 * This function is called whenever the recovery process ends. 130 * On success, the secret is returned in @a secret. 131 * 132 * @param cls closure 133 * @param rc error code 134 * @param secret contains the core secret which is passed to the user 135 * @param secret_size defines the size of the core secret 136 */ 137 static void 138 core_secret_cb (void *cls, 139 enum ANASTASIS_RecoveryStatus rc, 140 const void *secret, 141 size_t secret_size) 142 { 143 struct RecoverSecretState *rss = cls; 144 145 rss->recovery = NULL; 146 if (ANASTASIS_RS_SUCCESS != rc) 147 { 148 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 149 "Recovery failed with status %d\n", 150 rc); 151 TALER_TESTING_interpreter_fail (rss->is); 152 return; 153 } 154 if (0 != memcmp (secret, 155 rss->core_secret, 156 secret_size)) 157 { 158 GNUNET_break (0); 159 rss->recovered = GNUNET_SYSERR; 160 if (NULL != rss->recovery_task) 161 { 162 GNUNET_SCHEDULER_cancel (rss->recovery_task); 163 rss->recovery_task = NULL; 164 TALER_TESTING_interpreter_fail (rss->is); 165 } 166 return; 167 } 168 rss->recovered = GNUNET_OK; 169 if (NULL != rss->recovery_task) 170 { 171 GNUNET_SCHEDULER_cancel (rss->recovery_task); 172 rss->recovery_task = NULL; 173 TALER_TESTING_interpreter_next (rss->is); 174 } 175 } 176 177 178 /** 179 * Run a "recover secret" CMD. 180 * 181 * @param cls closure. 182 * @param cmd command currently being run. 183 * @param is interpreter state. 184 */ 185 static void 186 recover_secret_run (void *cls, 187 const struct TALER_TESTING_Command *cmd, 188 struct TALER_TESTING_Interpreter *is) 189 { 190 struct RecoverSecretState *rss = cls; 191 const struct TALER_TESTING_Command *ref; 192 const struct ANASTASIS_CRYPTO_ProviderSaltP *provider_salt; 193 rss->is = is; 194 195 GNUNET_assert (NULL != rss->download_reference); 196 ref = TALER_TESTING_interpreter_lookup_command ( 197 is, 198 rss->download_reference); 199 if (NULL == ref) 200 { 201 GNUNET_break (0); 202 TALER_TESTING_interpreter_fail (rss->is); 203 return; 204 } 205 if (GNUNET_OK != 206 ANASTASIS_TESTING_get_trait_provider_salt (ref, 207 &provider_salt)) 208 { 209 GNUNET_break (0); 210 TALER_TESTING_interpreter_fail (rss->is); 211 return; 212 } 213 if (NULL != rss->core_secret_reference) 214 { 215 ref = TALER_TESTING_interpreter_lookup_command ( 216 is, 217 rss->core_secret_reference); 218 if (NULL == ref) 219 { 220 GNUNET_break (0); 221 TALER_TESTING_interpreter_fail (rss->is); 222 return; 223 } 224 if (GNUNET_OK != 225 ANASTASIS_TESTING_get_trait_core_secret ( 226 ref, 227 &rss->core_secret)) 228 { 229 GNUNET_break (0); 230 TALER_TESTING_interpreter_fail (rss->is); 231 return; 232 } 233 } 234 rss->recovery = ANASTASIS_recovery_begin ( 235 TALER_TESTING_interpreter_get_context (is), 236 rss->id_data, 237 rss->version, 238 rss->anastasis_url, 239 provider_salt, 240 &policy_lookup_cb, 241 rss, 242 &core_secret_cb, 243 rss); 244 if (NULL == rss->recovery) 245 { 246 GNUNET_break (0); 247 TALER_TESTING_interpreter_fail (rss->is); 248 return; 249 } 250 } 251 252 253 /** 254 * Task to run the abort routine on the given @a cls object 255 * after the stack has fully unwound. 256 * 257 * @param cls a `struct ANASTASIS_Recovery *` 258 */ 259 static void 260 delayed_abort (void *cls) 261 { 262 struct ANASTASIS_Recovery *recovery = cls; 263 264 ANASTASIS_recovery_abort (recovery); 265 } 266 267 268 /** 269 * Free the state of a "recover secret" CMD, and possibly 270 * cancel it if it did not complete. 271 * 272 * @param cls closure 273 * @param cmd command being freed. 274 */ 275 static void 276 recover_secret_cleanup (void *cls, 277 const struct TALER_TESTING_Command *cmd) 278 { 279 struct RecoverSecretState *rss = cls; 280 281 if (NULL != rss->recovery) 282 { 283 /* must run first, or at least before #core_secret_cb */ 284 (void) GNUNET_SCHEDULER_add_with_priority ( 285 GNUNET_SCHEDULER_PRIORITY_SHUTDOWN, 286 &delayed_abort, 287 rss->recovery); 288 rss->recovery = NULL; 289 } 290 if (NULL != rss->recovery_task) 291 { 292 GNUNET_SCHEDULER_cancel (rss->recovery_task); 293 rss->recovery_task = NULL; 294 } 295 json_decref (rss->id_data); 296 GNUNET_free (rss); 297 } 298 299 300 /** 301 * Offer internal data to other commands. 302 * 303 * @param cls closure 304 * @param[out] ret result (could be anything) 305 * @param trait name of the trait 306 * @param index index number of the object to extract. 307 * @return #GNUNET_OK on success 308 */ 309 static enum GNUNET_GenericReturnValue 310 recover_secret_traits (void *cls, 311 const void **ret, 312 const char *trait, 313 unsigned int index) 314 { 315 struct RecoverSecretState *rss = cls; 316 317 if (NULL == rss->ri) 318 { 319 GNUNET_break (0); 320 return GNUNET_SYSERR; 321 } 322 if (index >= rss->ri->cs_len) 323 { 324 GNUNET_break (0); 325 return GNUNET_SYSERR; 326 } 327 { 328 struct TALER_TESTING_Trait traits[] = { 329 ANASTASIS_TESTING_make_trait_challenges ( 330 index, 331 (const struct ANASTASIS_Challenge **) &rss->ri->cs[index]), 332 TALER_TESTING_trait_end () 333 }; 334 335 return TALER_TESTING_get_trait (traits, 336 ret, 337 trait, 338 index); 339 } 340 } 341 342 343 /** 344 * Function called on timeout of the secret finishing operation. 345 * 346 * @param cls a `struct RecoverSecretState *` 347 */ 348 static void 349 recovery_fail (void *cls) 350 { 351 struct RecoverSecretState *rss = cls; 352 353 rss->recovery_task = NULL; 354 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 355 "Timeout during secret recovery\n"); 356 TALER_TESTING_interpreter_fail (rss->is); 357 } 358 359 360 /** 361 * Wait @a delay for @a cmd to finish secret recovery. 362 * 363 * @param cmd command to wait on 364 * @param delay how long to wait at most 365 */ 366 static void 367 recover_secret_finish (struct TALER_TESTING_Command *cmd, 368 struct GNUNET_TIME_Relative delay) 369 { 370 struct RecoverSecretState *rss = cmd->cls; 371 372 GNUNET_assert (&recover_secret_run == cmd->run); 373 GNUNET_assert (NULL == rss->recovery_task); 374 switch (rss->recovered) 375 { 376 case GNUNET_OK: 377 TALER_TESTING_interpreter_next (rss->is); 378 break; 379 case GNUNET_NO: 380 rss->recovery_task = GNUNET_SCHEDULER_add_delayed (delay, 381 &recovery_fail, 382 rss); 383 break; 384 case GNUNET_SYSERR: 385 TALER_TESTING_interpreter_fail (rss->is); 386 break; 387 } 388 } 389 390 391 struct TALER_TESTING_Command 392 ANASTASIS_TESTING_cmd_recover_secret ( 393 const char *label, 394 const char *anastasis_url, 395 const json_t *id_data, 396 unsigned int version, 397 enum ANASTASIS_TESTING_RecoverSecretOption rso, 398 const char *download_ref, 399 const char *core_secret_ref) 400 { 401 struct RecoverSecretState *rss; 402 403 rss = GNUNET_new (struct RecoverSecretState); 404 rss->version = version; 405 rss->id_data = json_incref ((json_t *) id_data); 406 rss->rsopt = rso; 407 rss->anastasis_url = anastasis_url; 408 rss->download_reference = download_ref; 409 rss->core_secret_reference = core_secret_ref; 410 { 411 struct TALER_TESTING_Command cmd = { 412 .cls = rss, 413 .label = label, 414 .run = &recover_secret_run, 415 .cleanup = &recover_secret_cleanup, 416 .traits = &recover_secret_traits 417 }; 418 419 return cmd; 420 } 421 } 422 423 424 /** 425 * State for a "recover secret finish" CMD. 426 */ 427 struct RecoverSecretFinishState 428 { 429 /** 430 * The interpreter state. 431 */ 432 struct TALER_TESTING_Interpreter *is; 433 434 /** 435 * URL of the anastasis backend. 436 */ 437 const char *recover_label; 438 439 /** 440 * Timeout. 441 */ 442 struct GNUNET_TIME_Relative timeout; 443 444 }; 445 446 447 /** 448 * Run a "recover secret finish" CMD. 449 * 450 * @param cls closure. 451 * @param cmd command currently being run. 452 * @param is interpreter state. 453 */ 454 static void 455 recover_secret_finish_run (void *cls, 456 const struct TALER_TESTING_Command *cmd, 457 struct TALER_TESTING_Interpreter *is) 458 { 459 struct RecoverSecretFinishState *rsfs = cls; 460 struct TALER_TESTING_Command *ref; 461 462 rsfs->is = is; 463 ref = (struct TALER_TESTING_Command *) 464 TALER_TESTING_interpreter_lookup_command (is, 465 rsfs->recover_label); 466 if (NULL == ref) 467 { 468 GNUNET_break (0); 469 TALER_TESTING_interpreter_fail (rsfs->is); 470 return; 471 } 472 recover_secret_finish (ref, 473 rsfs->timeout); 474 } 475 476 477 /** 478 * Free the state of a "recover secret finish" CMD, and possibly 479 * cancel it if it did not complete. 480 * 481 * @param cls closure 482 * @param cmd command being freed. 483 */ 484 static void 485 recover_secret_finish_cleanup (void *cls, 486 const struct TALER_TESTING_Command *cmd) 487 { 488 struct RecoverSecretFinishState *rsfs = cls; 489 490 GNUNET_free (rsfs); 491 } 492 493 494 struct TALER_TESTING_Command 495 ANASTASIS_TESTING_cmd_recover_secret_finish ( 496 const char *label, 497 const char *recover_label, 498 struct GNUNET_TIME_Relative timeout) 499 { 500 struct RecoverSecretFinishState *rsfs; 501 502 rsfs = GNUNET_new (struct RecoverSecretFinishState); 503 rsfs->recover_label = recover_label; 504 rsfs->timeout = timeout; 505 { 506 struct TALER_TESTING_Command cmd = { 507 .cls = rsfs, 508 .label = label, 509 .run = &recover_secret_finish_run, 510 .cleanup = &recover_secret_finish_cleanup 511 }; 512 513 return cmd; 514 } 515 } 516 517 518 /* end of testing_cmd_recover_secret.c */