LCOV - code coverage report
Current view: top level - testing - testing_cmd_recover_secret.c (source / functions) Hit Total Coverage
Test: GNU Taler anastasis coverage report Lines: 78 137 56.9 %
Date: 2021-06-16 06:33:01 Functions: 10 12 83.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :   This file is part of Anastasis
       3             :   Copyright (C) 2020, 2021 Taler Systems SA
       4             : 
       5             :   Anastasis is free software; you can redistribute it and/or modify it under the
       6             :   terms of the GNU Lesser 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 lib/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 lookup.
      51             :    */
      52             :   const char *download_reference;
      53             : 
      54             :   /**
      55             :    * Reference to download command we expect to lookup.
      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             :    * Salt to be used to derive the id
      71             :    */
      72             :   struct ANASTASIS_CRYPTO_ProviderSaltP *salt;
      73             : 
      74             :   /**
      75             :    * Recovery information from the lookup
      76             :    */
      77             :   struct ANASTASIS_RecoveryInformation *ri;
      78             : 
      79             :   /**
      80             :    * Coresecret to check if decryption worked
      81             :    */
      82             :   const void *core_secret;
      83             : 
      84             :   /**
      85             :    * Task scheduled to wait for recovery to complete.
      86             :    */
      87             :   struct GNUNET_SCHEDULER_Task *recovery_task;
      88             : 
      89             :   /**
      90             :    * version of the recovery document
      91             :    */
      92             :   unsigned int version;
      93             : 
      94             :   /**
      95             :    * #GNUNET_OK if the secret was recovered, #GNUNET_SYSERR if
      96             :    * recovery failed (yielded wrong secret).
      97             :    */
      98             :   int recovered;
      99             : };
     100             : 
     101             : 
     102             : /**
     103             :  * Callback which passes back the recovery document and its possible
     104             :  * policies. Also passes back the version of the document for the user
     105             :  * to check.
     106             :  *
     107             :  * @param cls closure for the callback
     108             :  * @param ri recovery information struct which contains the policies
     109             :  */
     110             : static void
     111           1 : policy_lookup_cb (void *cls,
     112             :                   const struct ANASTASIS_RecoveryInformation *ri)
     113             : {
     114           1 :   struct RecoverSecretState *rss = cls;
     115             : 
     116           1 :   rss->ri = (struct ANASTASIS_RecoveryInformation *) ri;
     117           1 :   if (NULL == ri)
     118             :   {
     119           0 :     GNUNET_break (0);
     120           0 :     TALER_TESTING_interpreter_fail (rss->is);
     121           0 :     return;
     122             :   }
     123           1 :   TALER_TESTING_interpreter_next (rss->is);
     124             : }
     125             : 
     126             : 
     127             : /**
     128             :  * This function is called whenever the recovery process ends.
     129             :  * On success, the secret is returned in @a secret.
     130             :  *
     131             :  * @param cls closure
     132             :  * @param ec error code
     133             :  * @param secret contains the core secret which is passed to the user
     134             :  * @param secret_size defines the size of the core secret
     135             :  */
     136             : static void
     137           1 : core_secret_cb (void *cls,
     138             :                 enum ANASTASIS_RecoveryStatus rc,
     139             :                 const void *secret,
     140             :                 size_t secret_size)
     141             : {
     142           1 :   struct RecoverSecretState *rss = cls;
     143             : 
     144           1 :   rss->recovery = NULL;
     145           1 :   if (ANASTASIS_RS_SUCCESS != rc)
     146             :   {
     147           0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     148             :                 "Recovery failed with status %d\n",
     149             :                 rc);
     150           0 :     TALER_TESTING_interpreter_fail (rss->is);
     151           0 :     return;
     152             :   }
     153           1 :   if (0 != memcmp (secret,
     154             :                    rss->core_secret,
     155             :                    secret_size))
     156             :   {
     157           0 :     GNUNET_break (0);
     158           0 :     rss->recovered = GNUNET_SYSERR;
     159           0 :     if (NULL != rss->recovery_task)
     160             :     {
     161           0 :       GNUNET_SCHEDULER_cancel (rss->recovery_task);
     162           0 :       rss->recovery_task = NULL;
     163           0 :       TALER_TESTING_interpreter_fail (rss->is);
     164             :     }
     165           0 :     return;
     166             :   }
     167           1 :   rss->recovered = GNUNET_OK;
     168           1 :   if (NULL != rss->recovery_task)
     169             :   {
     170           0 :     GNUNET_SCHEDULER_cancel (rss->recovery_task);
     171           0 :     rss->recovery_task = NULL;
     172           0 :     TALER_TESTING_interpreter_next (rss->is);
     173             :   }
     174             : }
     175             : 
     176             : 
     177             : /**
     178             :  * Run a "recover secret" CMD.
     179             :  *
     180             :  * @param cls closure.
     181             :  * @param cmd command currently being run.
     182             :  * @param is interpreter state.
     183             :  */
     184             : static void
     185           1 : recover_secret_run (void *cls,
     186             :                     const struct TALER_TESTING_Command *cmd,
     187             :                     struct TALER_TESTING_Interpreter *is)
     188             : {
     189           1 :   struct RecoverSecretState *rss = cls;
     190             :   const struct TALER_TESTING_Command *ref;
     191             :   const struct ANASTASIS_CRYPTO_ProviderSaltP *salt;
     192           1 :   rss->is = is;
     193             : 
     194           1 :   if (NULL != rss->download_reference)
     195             :   {
     196           1 :     ref = TALER_TESTING_interpreter_lookup_command
     197             :             (is,
     198             :             rss->download_reference);
     199           1 :     if (NULL == ref)
     200             :     {
     201           0 :       GNUNET_break (0);
     202           0 :       TALER_TESTING_interpreter_fail (rss->is);
     203           0 :       return;
     204             :     }
     205           1 :     if (GNUNET_OK !=
     206           1 :         ANASTASIS_TESTING_get_trait_salt (ref,
     207             :                                           0,
     208             :                                           &salt))
     209             :     {
     210           0 :       GNUNET_break (0);
     211           0 :       TALER_TESTING_interpreter_fail (rss->is);
     212           0 :       return;
     213             :     }
     214             :   }
     215           1 :   if (NULL != rss->core_secret_reference)
     216             :   {
     217           1 :     ref = TALER_TESTING_interpreter_lookup_command
     218             :             (is,
     219             :             rss->core_secret_reference);
     220           1 :     if (NULL == ref)
     221             :     {
     222           0 :       GNUNET_break (0);
     223           0 :       TALER_TESTING_interpreter_fail (rss->is);
     224           0 :       return;
     225             :     }
     226           1 :     if (GNUNET_OK !=
     227           1 :         ANASTASIS_TESTING_get_trait_core_secret (ref,
     228             :                                                  0,
     229             :                                                  &rss->core_secret))
     230             :     {
     231           0 :       GNUNET_break (0);
     232           0 :       TALER_TESTING_interpreter_fail (rss->is);
     233           0 :       return;
     234             :     }
     235             :   }
     236           2 :   rss->recovery = ANASTASIS_recovery_begin (is->ctx,
     237           1 :                                             rss->id_data,
     238             :                                             rss->version,
     239             :                                             rss->anastasis_url,
     240             :                                             salt,
     241             :                                             &policy_lookup_cb,
     242             :                                             rss,
     243             :                                             &core_secret_cb,
     244             :                                             rss);
     245           1 :   if (NULL == rss->recovery)
     246             :   {
     247           0 :     GNUNET_break (0);
     248           0 :     TALER_TESTING_interpreter_fail (rss->is);
     249           0 :     return;
     250             :   }
     251             : }
     252             : 
     253             : 
     254             : /**
     255             :  * Task to run the abort routine on the given @a cls object
     256             :  * after the stack has fully unwound.
     257             :  *
     258             :  * @param cls a `struct ANASTASIS_Recovery *`
     259             :  */
     260             : static void
     261           0 : delayed_abort (void *cls)
     262             : {
     263           0 :   struct ANASTASIS_Recovery *recovery = cls;
     264             : 
     265           0 :   ANASTASIS_recovery_abort (recovery);
     266           0 : }
     267             : 
     268             : 
     269             : /**
     270             :  * Free the state of a "recover secret" CMD, and possibly
     271             :  * cancel it if it did not complete.
     272             :  *
     273             :  * @param cls closure
     274             :  * @param cmd command being freed.
     275             :  */
     276             : static void
     277           1 : recover_secret_cleanup (void *cls,
     278             :                         const struct TALER_TESTING_Command *cmd)
     279             : {
     280           1 :   struct RecoverSecretState *rss = cls;
     281             : 
     282           1 :   if (NULL != rss->recovery)
     283             :   {
     284             :     /* must run first, or at least before #core_secret_cb */
     285           0 :     (void) GNUNET_SCHEDULER_add_with_priority (
     286             :       GNUNET_SCHEDULER_PRIORITY_SHUTDOWN,
     287             :       &delayed_abort,
     288           0 :       rss->recovery);
     289           0 :     rss->recovery = NULL;
     290             :   }
     291           1 :   if (NULL != rss->recovery_task)
     292             :   {
     293           0 :     GNUNET_SCHEDULER_cancel (rss->recovery_task);
     294           0 :     rss->recovery_task = NULL;
     295             :   }
     296           1 :   json_decref (rss->id_data);
     297           1 :   GNUNET_free (rss);
     298           1 : }
     299             : 
     300             : 
     301             : /**
     302             :  * Offer internal data to other commands.
     303             :  *
     304             :  * @param cls closure
     305             :  * @param ret[out] result (could be anything)
     306             :  * @param trait name of the trait
     307             :  * @param index index number of the object to extract.
     308             :  * @return #GNUNET_OK on success
     309             :  */
     310             : static int
     311           4 : recover_secret_traits (void *cls,
     312             :                        const void **ret,
     313             :                        const char *trait,
     314             :                        unsigned int index)
     315             : {
     316           4 :   struct RecoverSecretState *rss = cls;
     317             : 
     318           4 :   if (NULL == rss->ri)
     319             :   {
     320           0 :     GNUNET_break (0);
     321           0 :     return GNUNET_SYSERR;
     322             :   }
     323           4 :   if (index >= rss->ri->cs_len)
     324             :   {
     325           0 :     GNUNET_break (0);
     326           0 :     return GNUNET_SYSERR;
     327             :   }
     328             :   {
     329             :     struct TALER_TESTING_Trait traits[] = {
     330           4 :       ANASTASIS_TESTING_make_trait_challenge (index,
     331           4 :                                               rss->ri->cs[index]),
     332           4 :       TALER_TESTING_trait_end ()
     333             :     };
     334             : 
     335           4 :     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           0 : recovery_fail (void *cls)
     350             : {
     351           0 :   struct RecoverSecretState *rss = cls;
     352             : 
     353           0 :   rss->recovery_task = NULL;
     354           0 :   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     355             :               "Timeout during secret recovery\n");
     356           0 :   TALER_TESTING_interpreter_fail (rss->is);
     357           0 : }
     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           1 : recover_secret_finish (struct TALER_TESTING_Command *cmd,
     368             :                        struct GNUNET_TIME_Relative delay)
     369             : {
     370           1 :   struct RecoverSecretState *rss = cmd->cls;
     371             : 
     372           1 :   GNUNET_assert (&recover_secret_run == cmd->run);
     373           1 :   GNUNET_assert (NULL == rss->recovery_task);
     374           1 :   switch (rss->recovered)
     375             :   {
     376           1 :   case GNUNET_OK:
     377           1 :     TALER_TESTING_interpreter_next (rss->is);
     378           1 :     break;
     379           0 :   case GNUNET_NO:
     380           0 :     rss->recovery_task = GNUNET_SCHEDULER_add_delayed (delay,
     381             :                                                        &recovery_fail,
     382             :                                                        rss);
     383           0 :     break;
     384           0 :   case GNUNET_SYSERR:
     385           0 :     TALER_TESTING_interpreter_fail (rss->is);
     386           0 :     break;
     387             :   }
     388           1 : }
     389             : 
     390             : 
     391             : struct TALER_TESTING_Command
     392           1 : 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           1 :   rss = GNUNET_new (struct RecoverSecretState);
     404           1 :   rss->version = version;
     405           1 :   rss->id_data = json_incref ((json_t *) id_data);
     406           1 :   rss->rsopt = rso;
     407           1 :   rss->anastasis_url = anastasis_url;
     408           1 :   rss->download_reference = download_ref;
     409           1 :   rss->core_secret_reference = core_secret_ref;
     410             :   {
     411           1 :     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           1 :     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           1 : recover_secret_finish_run (void *cls,
     456             :                            const struct TALER_TESTING_Command *cmd,
     457             :                            struct TALER_TESTING_Interpreter *is)
     458             : {
     459           1 :   struct RecoverSecretFinishState *rsfs = cls;
     460             :   struct TALER_TESTING_Command *ref;
     461             : 
     462           1 :   rsfs->is = is;
     463             :   ref = (struct TALER_TESTING_Command *)
     464           1 :         TALER_TESTING_interpreter_lookup_command (is,
     465             :                                                   rsfs->recover_label);
     466           1 :   if (NULL == ref)
     467             :   {
     468           0 :     GNUNET_break (0);
     469           0 :     TALER_TESTING_interpreter_fail (rsfs->is);
     470           0 :     return;
     471             :   }
     472           1 :   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           1 : recover_secret_finish_cleanup (void *cls,
     486             :                                const struct TALER_TESTING_Command *cmd)
     487             : {
     488           1 :   struct RecoverSecretFinishState *rsfs = cls;
     489             : 
     490           1 :   GNUNET_free (rsfs);
     491           1 : }
     492             : 
     493             : 
     494             : struct TALER_TESTING_Command
     495           1 : 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           1 :   rsfs = GNUNET_new (struct RecoverSecretFinishState);
     503           1 :   rsfs->recover_label = recover_label;
     504           1 :   rsfs->timeout = timeout;
     505             :   {
     506           1 :     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           1 :     return cmd;
     514             :   }
     515             : }
     516             : 
     517             : 
     518             : /* end of testing_cmd_recover_secret.c */

Generated by: LCOV version 1.14