anastasis

Credential backup and recovery protocol and service
Log | Files | Refs | Submodules | README | LICENSE

testing_cmd_challenge_answer.c (16610B)


      1 /*
      2   This file is part of Anastasis
      3   Copyright (C) 2020, 2021, 2022 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_challenge_answer.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 #include <taler/taler_merchant_service.h>
     28 
     29 
     30 // FIXME: break up into two files, one for start, one for answer!
     31 
     32 /**
     33  * State for a "challenge answer" CMD.
     34  */
     35 struct ChallengeState
     36 {
     37   /**
     38    * The interpreter state.
     39    */
     40   struct TALER_TESTING_Interpreter *is;
     41 
     42   /**
     43    * Reference to the challenge we are solving
     44    */
     45   struct ANASTASIS_Challenge *c;
     46 
     47   /**
     48    * Answer to the challenge we are solving
     49    */
     50   const char *answer;
     51 
     52   /**
     53    * Reference to the recovery process
     54    */
     55   const char *challenge_ref;
     56 
     57   /**
     58    * Reference to the payment
     59    */
     60   const char *payment_ref;
     61 
     62   /**
     63    * "taler://pay/" URL we got back, if any. Otherwise NULL.
     64    */
     65   char *payment_uri;
     66 
     67   /**
     68    * Order ID extracted from @e payment_uri, or NULL.
     69    */
     70   char *order_id;
     71 
     72   /**
     73    * Payment order ID we are to provide in the request.
     74    */
     75   struct ANASTASIS_PaymentSecretP payment_order_req;
     76 
     77   /**
     78    * Expected answer status code.
     79    */
     80   enum ANASTASIS_ChallengeAnswerStatus expected_acs;
     81 
     82   /**
     83    * Expected start status code.
     84    */
     85   enum ANASTASIS_ChallengeStartStatus expected_scs;
     86 
     87   /**
     88    * Index of the challenge we are solving
     89    */
     90   unsigned int challenge_index;
     91 
     92   /**
     93    * 0 for no plugin needed 1 for plugin needed to authenticate
     94    */
     95   unsigned int mode;
     96 
     97   /**
     98    * code we read in the file generated by the plugin
     99    */
    100   char *code;
    101 
    102 };
    103 
    104 
    105 static void
    106 challenge_answer_cb (void *af_cls,
    107                      const struct ANASTASIS_ChallengeAnswerResponse *csr)
    108 {
    109   struct ChallengeState *cs = af_cls;
    110 
    111   cs->c = NULL;
    112   if (csr->cs != cs->expected_acs)
    113   {
    114     GNUNET_break (0);
    115     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    116                 "Expected status %u, got %u\n",
    117                 cs->expected_acs,
    118                 csr->cs);
    119     TALER_TESTING_interpreter_fail (cs->is);
    120     return;
    121   }
    122   switch (csr->cs)
    123   {
    124   case ANASTASIS_CHALLENGE_ANSWER_STATUS_SOLVED:
    125     break;
    126   case ANASTASIS_CHALLENGE_ANSWER_STATUS_INVALID_ANSWER:
    127     break;
    128   case ANASTASIS_CHALLENGE_ANSWER_STATUS_PAYMENT_REQUIRED:
    129     if (0 != strncmp (csr->details.payment_required.taler_pay_uri,
    130                       "taler+http://pay/",
    131                       strlen ("taler+http://pay/")))
    132     {
    133       GNUNET_break (0);
    134       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    135                   "Invalid payment URI `%s'\n",
    136                   csr->details.payment_required.taler_pay_uri);
    137       TALER_TESTING_interpreter_fail (cs->is);
    138       return;
    139     }
    140     cs->payment_uri = GNUNET_strdup (
    141       csr->details.payment_required.taler_pay_uri);
    142     {
    143       struct TALER_MERCHANT_PayUriData pud;
    144 
    145       if (GNUNET_OK !=
    146           TALER_MERCHANT_parse_pay_uri (cs->payment_uri,
    147                                         &pud))
    148       {
    149         GNUNET_break (0);
    150         TALER_TESTING_interpreter_fail (cs->is);
    151         return;
    152       }
    153       cs->order_id = GNUNET_strdup (pud.order_id);
    154       if (GNUNET_OK !=
    155           GNUNET_STRINGS_string_to_data (cs->order_id,
    156                                          strlen (cs->order_id),
    157                                          &cs->payment_order_req,
    158                                          sizeof (cs->payment_order_req)))
    159       {
    160         GNUNET_break (0);
    161         TALER_TESTING_interpreter_fail (cs->is);
    162         return;
    163       }
    164       TALER_MERCHANT_parse_pay_uri_free (&pud);
    165     }
    166     TALER_TESTING_interpreter_next (cs->is);
    167     return;
    168   case ANASTASIS_CHALLENGE_ANSWER_STATUS_TRUTH_UNKNOWN:
    169     break;
    170   case ANASTASIS_CHALLENGE_ANSWER_STATUS_SERVER_FAILURE:
    171     GNUNET_break (0);
    172     TALER_TESTING_interpreter_fail (cs->is);
    173     return;
    174   case ANASTASIS_CHALLENGE_ANSWER_STATUS_RATE_LIMIT_EXCEEDED:
    175     break;
    176   }
    177   TALER_TESTING_interpreter_next (cs->is);
    178 }
    179 
    180 
    181 /**
    182  * Run a "recover secret" CMD.
    183  *
    184  * @param cls closure.
    185  * @param cmd command currently being run.
    186  * @param is interpreter state.
    187  */
    188 static void
    189 challenge_answer_run (void *cls,
    190                       const struct TALER_TESTING_Command *cmd,
    191                       struct TALER_TESTING_Interpreter *is)
    192 {
    193   struct ChallengeState *cs = cls;
    194   const struct ANASTASIS_Challenge **c;
    195   const struct ANASTASIS_PaymentSecretP *ps;
    196 
    197   cs->is = is;
    198   if (NULL != cs->challenge_ref)
    199   {
    200     const struct TALER_TESTING_Command *ref;
    201 
    202     ref = TALER_TESTING_interpreter_lookup_command (
    203       is,
    204       cs->challenge_ref);
    205     if (NULL == ref)
    206     {
    207       GNUNET_break (0);
    208       TALER_TESTING_interpreter_fail (cs->is);
    209       return;
    210     }
    211     if (GNUNET_OK !=
    212         ANASTASIS_TESTING_get_trait_challenges (ref,
    213                                                 cs->challenge_index,
    214                                                 &c))
    215     {
    216       GNUNET_break (0);
    217       TALER_TESTING_interpreter_fail (cs->is);
    218       return;
    219     }
    220     cs->c = (struct ANASTASIS_Challenge *) *c;
    221   }
    222 
    223   if (NULL != cs->payment_ref)
    224   {
    225     const struct TALER_TESTING_Command *ref;
    226 
    227     ref = TALER_TESTING_interpreter_lookup_command (is,
    228                                                     cs->payment_ref);
    229     if (NULL == ref)
    230     {
    231       GNUNET_break (0);
    232       TALER_TESTING_interpreter_fail (cs->is);
    233       return;
    234     }
    235     if (GNUNET_OK !=
    236         ANASTASIS_TESTING_get_trait_payment_secret (ref,
    237                                                     &ps))
    238     {
    239       GNUNET_break (0);
    240       TALER_TESTING_interpreter_fail (cs->is);
    241       return;
    242     }
    243   }
    244   else
    245   {
    246     ps = NULL;
    247   }
    248 
    249   if (1 == cs->mode)
    250   {
    251     const struct TALER_TESTING_Command *ref;
    252     const char *answer;
    253     unsigned long long code;
    254     char dummy;
    255 
    256     ref = TALER_TESTING_interpreter_lookup_command (is,
    257                                                     cs->answer);
    258     if (NULL == ref)
    259     {
    260       GNUNET_break (0);
    261       TALER_TESTING_interpreter_fail (cs->is);
    262       return;
    263     }
    264     if (GNUNET_OK !=
    265         ANASTASIS_TESTING_get_trait_code (ref,
    266                                           &answer))
    267     {
    268       GNUNET_break (0);
    269       TALER_TESTING_interpreter_fail (cs->is);
    270       return;
    271     }
    272     if (1 !=
    273         sscanf (answer,
    274                 "%llu%c",
    275                 &code,
    276                 &dummy))
    277     {
    278       GNUNET_break (0);
    279       TALER_TESTING_interpreter_fail (cs->is);
    280       return;
    281     }
    282     if (GNUNET_OK !=
    283         ANASTASIS_challenge_answer2 (cs->c,
    284                                      ps,
    285                                      GNUNET_TIME_UNIT_ZERO,
    286                                      code,
    287                                      &challenge_answer_cb,
    288                                      cs))
    289     {
    290       GNUNET_break (0);
    291       cs->c = NULL;
    292       TALER_TESTING_interpreter_fail (cs->is);
    293       return;
    294     }
    295 
    296   }
    297   else
    298   {
    299     if (GNUNET_OK !=
    300         ANASTASIS_challenge_answer (cs->c,
    301                                     ps,
    302                                     GNUNET_TIME_UNIT_ZERO,
    303                                     cs->answer,
    304                                     &challenge_answer_cb,
    305                                     cs))
    306     {
    307       GNUNET_break (0);
    308       cs->c = NULL;
    309       TALER_TESTING_interpreter_fail (cs->is);
    310       return;
    311     }
    312   }
    313 }
    314 
    315 
    316 static void
    317 challenge_start_cb (void *af_cls,
    318                     const struct ANASTASIS_ChallengeStartResponse *csr)
    319 {
    320   struct ChallengeState *cs = af_cls;
    321 
    322   cs->c = NULL;
    323   if (csr->cs != cs->expected_scs)
    324   {
    325     GNUNET_break (0);
    326     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    327                 "Expected status %u, got %u\n",
    328                 cs->expected_scs,
    329                 csr->cs);
    330     TALER_TESTING_interpreter_fail (cs->is);
    331     return;
    332   }
    333   switch (csr->cs)
    334   {
    335   case ANASTASIS_CHALLENGE_START_STATUS_FILENAME_PROVIDED:
    336     {
    337       FILE *file;
    338       char code[22];
    339 
    340       file = fopen (csr->details.tan_filename,
    341                     "r");
    342       if (NULL == file)
    343       {
    344         GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
    345                                   "open",
    346                                   csr->details.tan_filename);
    347         TALER_TESTING_interpreter_fail (cs->is);
    348         return;
    349       }
    350       if (0 == fscanf (file,
    351                        "%21s",
    352                        code))
    353       {
    354         GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
    355                                   "fscanf",
    356                                   csr->details.tan_filename);
    357         GNUNET_break (0 == fclose (file));
    358         TALER_TESTING_interpreter_fail (cs->is);
    359         return;
    360       }
    361       GNUNET_break (0 == fclose (file));
    362       cs->code = GNUNET_strdup (code);
    363       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
    364                   "Read code `%s'\n",
    365                   code);
    366     }
    367     break;
    368   case ANASTASIS_CHALLENGE_START_STATUS_TAN_SENT_HINT_PROVIDED:
    369     GNUNET_break (0); /* FIXME: not implemented */
    370     break;
    371   case ANASTASIS_CHALLENGE_START_STATUS_TAN_ALREADY_SENT:
    372     GNUNET_break (0); /* FIXME: not implemented */
    373     break;
    374   case ANASTASIS_CHALLENGE_START_STATUS_BANK_TRANSFER_REQUIRED:
    375     GNUNET_break (0); /* FIXME: not implemented */
    376     break;
    377   case ANASTASIS_CHALLENGE_START_STATUS_PAYMENT_REQUIRED:
    378     if (0 != strncmp (csr->details.payment_required.taler_pay_uri,
    379                       "taler+http://pay/",
    380                       strlen ("taler+http://pay/")))
    381     {
    382       GNUNET_break (0);
    383       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    384                   "Invalid payment URI `%s'\n",
    385                   csr->details.payment_required.taler_pay_uri);
    386       TALER_TESTING_interpreter_fail (cs->is);
    387       return;
    388     }
    389     cs->payment_uri = GNUNET_strdup (
    390       csr->details.payment_required.taler_pay_uri);
    391     {
    392       struct TALER_MERCHANT_PayUriData pud;
    393 
    394       if (GNUNET_OK !=
    395           TALER_MERCHANT_parse_pay_uri (cs->payment_uri,
    396                                         &pud))
    397       {
    398         GNUNET_break (0);
    399         TALER_TESTING_interpreter_fail (cs->is);
    400         return;
    401       }
    402       cs->order_id = GNUNET_strdup (pud.order_id);
    403       if (GNUNET_OK !=
    404           GNUNET_STRINGS_string_to_data (cs->order_id,
    405                                          strlen (cs->order_id),
    406                                          &cs->payment_order_req,
    407                                          sizeof (cs->payment_order_req)))
    408       {
    409         GNUNET_break (0);
    410         TALER_TESTING_interpreter_fail (cs->is);
    411         return;
    412       }
    413       TALER_MERCHANT_parse_pay_uri_free (&pud);
    414     }
    415     TALER_TESTING_interpreter_next (cs->is);
    416     return;
    417   case ANASTASIS_CHALLENGE_START_STATUS_TRUTH_UNKNOWN:
    418     break;
    419   case ANASTASIS_CHALLENGE_START_STATUS_SERVER_FAILURE:
    420     GNUNET_break (0);
    421     TALER_TESTING_interpreter_fail (cs->is);
    422     return;
    423   }
    424   TALER_TESTING_interpreter_next (cs->is);
    425 }
    426 
    427 
    428 /**
    429  * Run a "recover secret" CMD.
    430  *
    431  * @param cls closure.
    432  * @param cmd command currently being run.
    433  * @param is interpreter state.
    434  */
    435 static void
    436 challenge_start_run (void *cls,
    437                      const struct TALER_TESTING_Command *cmd,
    438                      struct TALER_TESTING_Interpreter *is)
    439 {
    440   struct ChallengeState *cs = cls;
    441   const struct ANASTASIS_Challenge **c;
    442   const struct ANASTASIS_PaymentSecretP *ps;
    443 
    444   cs->is = is;
    445   {
    446     const struct TALER_TESTING_Command *ref;
    447 
    448     ref = TALER_TESTING_interpreter_lookup_command (
    449       is,
    450       cs->challenge_ref);
    451     if (NULL == ref)
    452     {
    453       GNUNET_break (0);
    454       TALER_TESTING_interpreter_fail (cs->is);
    455       return;
    456     }
    457     if (GNUNET_OK !=
    458         ANASTASIS_TESTING_get_trait_challenges (ref,
    459                                                 cs->challenge_index,
    460                                                 &c))
    461     {
    462       GNUNET_break (0);
    463       TALER_TESTING_interpreter_fail (cs->is);
    464       return;
    465     }
    466   }
    467 
    468   if (NULL != cs->payment_ref)
    469   {
    470     const struct TALER_TESTING_Command *pref;
    471 
    472     pref = TALER_TESTING_interpreter_lookup_command (is,
    473                                                      cs->payment_ref);
    474     if (NULL == pref)
    475     {
    476       GNUNET_break (0);
    477       TALER_TESTING_interpreter_fail (cs->is);
    478       return;
    479     }
    480     if (GNUNET_OK !=
    481         ANASTASIS_TESTING_get_trait_payment_secret (pref,
    482                                                     &ps))
    483     {
    484       GNUNET_break (0);
    485       TALER_TESTING_interpreter_fail (cs->is);
    486       return;
    487     }
    488   }
    489   else
    490   {
    491     ps = NULL;
    492   }
    493   if (GNUNET_OK !=
    494       ANASTASIS_challenge_start ((struct ANASTASIS_Challenge *) *c,
    495                                  ps,
    496                                  &challenge_start_cb,
    497                                  cs))
    498   {
    499     GNUNET_break (0);
    500     TALER_TESTING_interpreter_fail (cs->is);
    501     return;
    502   }
    503 }
    504 
    505 
    506 /**
    507  * Free the state of a "recover secret" CMD, and possibly
    508  * cancel it if it did not complete.
    509  *
    510  * @param cls closure.
    511  * @param cmd command being freed.
    512  */
    513 static void
    514 challenge_cleanup (void *cls,
    515                    const struct TALER_TESTING_Command *cmd)
    516 {
    517   struct ChallengeState *cs = cls;
    518 
    519   if (NULL != cs->c)
    520   {
    521     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    522                 "Command '%s' did not complete (challenge answer)\n",
    523                 cmd->label);
    524     ANASTASIS_challenge_abort (cs->c);
    525     cs->c = NULL;
    526   }
    527   GNUNET_free (cs->payment_uri);
    528   GNUNET_free (cs->order_id);
    529   GNUNET_free (cs->code);
    530   GNUNET_free (cs);
    531 }
    532 
    533 
    534 /**
    535  * Offer internal data to other commands.
    536  *
    537  * @param cls closure
    538  * @param[out] ret result (could be anything)
    539  * @param trait name of the trait
    540  * @param index index number of the object to extract.
    541  * @return #GNUNET_OK on success
    542  */
    543 static enum GNUNET_GenericReturnValue
    544 challenge_create_traits (void *cls,
    545                          const void **ret,
    546                          const char *trait,
    547                          unsigned int index)
    548 {
    549   struct ChallengeState *cs = cls;
    550   struct TALER_TESTING_Trait traits[] = {
    551     ANASTASIS_TESTING_make_trait_code (cs->code),
    552     ANASTASIS_TESTING_make_trait_payment_secret (
    553       &cs->payment_order_req),
    554     TALER_TESTING_make_trait_taler_uri (cs->payment_uri),
    555     TALER_TESTING_make_trait_order_id (cs->order_id),
    556     TALER_TESTING_trait_end ()
    557   };
    558 
    559   return TALER_TESTING_get_trait (traits,
    560                                   ret,
    561                                   trait,
    562                                   index);
    563 }
    564 
    565 
    566 struct TALER_TESTING_Command
    567 ANASTASIS_TESTING_cmd_challenge_start (
    568   const char *label,
    569   const char *payment_ref,
    570   const char *challenge_ref,
    571   unsigned int challenge_index,
    572   enum ANASTASIS_ChallengeStartStatus expected_cs)
    573 {
    574   struct ChallengeState *cs;
    575 
    576   cs = GNUNET_new (struct ChallengeState);
    577   cs->expected_scs = expected_cs;
    578   cs->challenge_ref = challenge_ref;
    579   cs->payment_ref = payment_ref;
    580   cs->challenge_index = challenge_index;
    581   {
    582     struct TALER_TESTING_Command cmd = {
    583       .cls = cs,
    584       .label = label,
    585       .run = &challenge_start_run,
    586       .cleanup = &challenge_cleanup,
    587       .traits = &challenge_create_traits
    588     };
    589 
    590     return cmd;
    591   }
    592 }
    593 
    594 
    595 struct TALER_TESTING_Command
    596 ANASTASIS_TESTING_cmd_challenge_answer (
    597   const char *label,
    598   const char *payment_ref,
    599   const char *challenge_ref,
    600   unsigned int challenge_index,
    601   const char *answer,
    602   unsigned int mode,
    603   enum ANASTASIS_ChallengeAnswerStatus expected_cs)
    604 {
    605   struct ChallengeState *cs;
    606 
    607   cs = GNUNET_new (struct ChallengeState);
    608   cs->expected_acs = expected_cs;
    609   cs->challenge_ref = challenge_ref;
    610   cs->payment_ref = payment_ref;
    611   cs->answer = answer;
    612   cs->challenge_index = challenge_index;
    613   cs->mode = mode;
    614   {
    615     struct TALER_TESTING_Command cmd = {
    616       .cls = cs,
    617       .label = label,
    618       .run = &challenge_answer_run,
    619       .cleanup = &challenge_cleanup,
    620       .traits = &challenge_create_traits
    621     };
    622 
    623     return cmd;
    624   }
    625 }
    626 
    627 
    628 /* end of testing_cmd_challenge_answer.c */