anastasis

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

testing_api_cmd_truth_store.c (11721B)


      1 /*
      2   This file is part of Anastasis
      3   Copyright (C) 2020 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_api_cmd_truth_store.c
     18  * @brief command to execute the anastasis backend service.
     19  * @author Dennis Neufeld
     20  */
     21 #include "platform.h"
     22 struct TruthStoreState;
     23 #define ANASTASIS_TRUTH_STORE_RESULT_CLOSURE struct TruthStoreState
     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  * State for a "truth store" CMD.
     31  */
     32 struct TruthStoreState
     33 {
     34   /**
     35    * UUID of the uploaded truth
     36    */
     37   struct ANASTASIS_CRYPTO_TruthUUIDP uuid;
     38 
     39   /**
     40    * Key used to encrypt the @e truth_data on the server.
     41    */
     42   struct ANASTASIS_CRYPTO_TruthKeyP key;
     43 
     44   /**
     45    * "Encrypted" key share data we store at the server.
     46    */
     47   struct ANASTASIS_CRYPTO_EncryptedKeyShareP encrypted_keyshare;
     48 
     49   /**
     50    * The /truth POST operation handle.
     51    */
     52   struct ANASTASIS_TruthStoreOperation *tso;
     53 
     54   /**
     55    * URL of the anastasis backend.
     56    */
     57   const char *anastasis_url;
     58 
     59   /**
     60    * The interpreter state.
     61    */
     62   struct TALER_TESTING_Interpreter *is;
     63 
     64   /**
     65    * Previous upload, or NULL for none. Used to calculate what THIS
     66    * upload is based on.
     67    */
     68   const char *prev_upload;
     69 
     70   /**
     71    * Authorization method / plugin name.
     72    */
     73   const char *method;
     74 
     75   /**
     76    * Mimetype of @e truth_data.
     77    */
     78   const char *mime_type;
     79 
     80   /**
     81    * Number of bytes in @e truth_data
     82    */
     83   size_t truth_data_size;
     84 
     85   /**
     86    * Data used by the authorization process.
     87    */
     88   void *truth_data;
     89 
     90   /**
     91    * Name of the file where the service will write the challenge, or NULL.
     92    */
     93   char *filename;
     94 
     95   /**
     96    * Expected status code.
     97    */
     98   unsigned int http_status;
     99 
    100   /**
    101    * Payment request we got back, or NULL.
    102    */
    103   char *pay_uri;
    104 
    105   /**
    106    * Payment order ID we got back, or all zeros.
    107    */
    108   struct ANASTASIS_PaymentSecretP payment_secret_response;
    109 
    110   /**
    111    * Options for how we are supposed to do the upload.
    112    */
    113   enum ANASTASIS_TESTING_TruthStoreOption tsopt;
    114 };
    115 
    116 /**
    117  * Function called with the results of an #ANASTASIS_truth_store()
    118  * operation.
    119  *
    120  * @param tss closure
    121  * @param ud details about the upload operation
    122  */
    123 static void
    124 truth_store_cb (struct TruthStoreState *tss,
    125                 const struct ANASTASIS_UploadDetails *ud)
    126 {
    127   tss->tso = NULL;
    128   if (ud->http_status != tss->http_status)
    129   {
    130     TALER_TESTING_unexpected_status (tss->is,
    131                                      ud->http_status,
    132                                      tss->http_status);
    133     return;
    134   }
    135   switch (ud->us)
    136   {
    137   case ANASTASIS_US_SUCCESS:
    138     break;
    139   case ANASTASIS_US_PAYMENT_REQUIRED:
    140     tss->pay_uri = GNUNET_strdup (ud->details.payment.payment_request);
    141     tss->payment_secret_response = ud->details.payment.ps;
    142     break;
    143   case ANASTASIS_US_CONFLICTING_TRUTH:
    144     GNUNET_break (0);
    145     TALER_TESTING_interpreter_fail (tss->is);
    146     return;
    147   case ANASTASIS_US_HTTP_ERROR:
    148     GNUNET_break (0);
    149     TALER_TESTING_interpreter_fail (tss->is);
    150     return;
    151   case ANASTASIS_US_CLIENT_ERROR:
    152     GNUNET_break (0);
    153     TALER_TESTING_interpreter_fail (tss->is);
    154     return;
    155   case ANASTASIS_US_SERVER_ERROR:
    156     GNUNET_break (0);
    157     TALER_TESTING_interpreter_fail (tss->is);
    158     return;
    159   default:
    160     GNUNET_break (0);
    161     TALER_TESTING_interpreter_fail (tss->is);
    162     return;
    163   }
    164   TALER_TESTING_interpreter_next (tss->is);
    165 }
    166 
    167 
    168 /**
    169  * Run a "truth store" CMD.
    170  *
    171  * @param cls closure.
    172  * @param cmd command currently being run.
    173  * @param is interpreter state.
    174  */
    175 static void
    176 truth_store_run (void *cls,
    177                  const struct TALER_TESTING_Command *cmd,
    178                  struct TALER_TESTING_Interpreter *is)
    179 {
    180   struct TruthStoreState *tss = cls;
    181 
    182   tss->is = is;
    183   if (NULL != tss->prev_upload)
    184   {
    185     const struct TALER_TESTING_Command *ref;
    186 
    187     ref = TALER_TESTING_interpreter_lookup_command (is,
    188                                                     tss->prev_upload);
    189     if (NULL == ref)
    190     {
    191       GNUNET_break (0);
    192       TALER_TESTING_interpreter_fail (tss->is);
    193       return;
    194     }
    195 
    196     if (0 != (ANASTASIS_TESTING_TSO_REFERENCE_UUID & tss->tsopt))
    197     {
    198       const struct ANASTASIS_CRYPTO_TruthUUIDP *uuid;
    199       const struct ANASTASIS_CRYPTO_EncryptedKeyShareP *eks;
    200 
    201       if (GNUNET_OK !=
    202           ANASTASIS_TESTING_get_trait_truth_uuid (ref,
    203                                                   &uuid))
    204       {
    205         GNUNET_break (0);
    206         TALER_TESTING_interpreter_fail (tss->is);
    207         return;
    208       }
    209       tss->uuid = *uuid;
    210       if (GNUNET_OK !=
    211           ANASTASIS_TESTING_get_trait_eks (ref,
    212                                            &eks))
    213       {
    214         GNUNET_break (0);
    215         TALER_TESTING_interpreter_fail (tss->is);
    216         return;
    217       }
    218       tss->encrypted_keyshare = *eks;
    219     }
    220   }
    221   else
    222   {
    223     GNUNET_CRYPTO_random_block (&tss->uuid,
    224                                 sizeof (struct ANASTASIS_CRYPTO_TruthUUIDP));
    225     GNUNET_CRYPTO_random_block (
    226       &tss->encrypted_keyshare,
    227       sizeof (struct ANASTASIS_CRYPTO_EncryptedKeyShareP));
    228   }
    229   GNUNET_CRYPTO_random_block (
    230     &tss->key,
    231     sizeof (struct ANASTASIS_CRYPTO_TruthKeyP));
    232 
    233   {
    234     void *encrypted_truth;
    235     size_t size_encrypted_truth;
    236     struct ANASTASIS_CRYPTO_NonceP nonce;
    237 
    238     GNUNET_CRYPTO_random_block (&nonce,
    239                                 sizeof (nonce));
    240     ANASTASIS_CRYPTO_truth_encrypt (&nonce,
    241                                     &tss->key,
    242                                     tss->truth_data,
    243                                     tss->truth_data_size,
    244                                     &encrypted_truth,
    245                                     &size_encrypted_truth);
    246     {
    247       void *t;
    248       size_t t_size;
    249 
    250       if (GNUNET_OK !=
    251           ANASTASIS_CRYPTO_truth_decrypt (&tss->key,
    252                                           encrypted_truth,
    253                                           size_encrypted_truth,
    254                                           &t,
    255                                           &t_size))
    256       {
    257         GNUNET_break (0);
    258         TALER_TESTING_interpreter_fail (tss->is);
    259         return;
    260       }
    261       if ( (t_size != tss->truth_data_size) ||
    262            (0 != memcmp (tss->truth_data,
    263                          t,
    264                          t_size)) )
    265       {
    266         GNUNET_break (0);
    267         TALER_TESTING_interpreter_fail (tss->is);
    268         return;
    269       }
    270       GNUNET_free (t);
    271     }
    272     tss->tso = ANASTASIS_truth_store (
    273       TALER_TESTING_interpreter_get_context (is),
    274       tss->anastasis_url,
    275       &tss->uuid,
    276       tss->method,
    277       &tss->encrypted_keyshare,
    278       tss->mime_type,
    279       size_encrypted_truth,
    280       encrypted_truth,
    281       (0 != (ANASTASIS_TESTING_TSO_REQUEST_PAYMENT & tss->tsopt)),
    282       GNUNET_TIME_UNIT_ZERO,
    283       &truth_store_cb,
    284       tss);
    285     GNUNET_free (encrypted_truth);
    286   }
    287   if (NULL == tss->tso)
    288   {
    289     GNUNET_break (0);
    290     TALER_TESTING_interpreter_fail (tss->is);
    291     return;
    292   }
    293 }
    294 
    295 
    296 /**
    297  * Free the state of a "truth store" CMD, and possibly
    298  * cancel it if it did not complete.
    299  *
    300  * @param cls closure.
    301  * @param cmd command being freed.
    302  */
    303 static void
    304 truth_store_cleanup (void *cls,
    305                      const struct TALER_TESTING_Command *cmd)
    306 {
    307   struct TruthStoreState *tss = cls;
    308 
    309   if (NULL != tss->tso)
    310   {
    311     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    312                 "Command '%s' did not complete (truth post)\n",
    313                 cmd->label);
    314     ANASTASIS_truth_store_cancel (tss->tso);
    315     tss->tso = NULL;
    316   }
    317   GNUNET_free (tss->truth_data);
    318   GNUNET_free (tss->pay_uri);
    319   GNUNET_free (tss->filename);
    320   GNUNET_free (tss);
    321 }
    322 
    323 
    324 /**
    325  * Offer internal data to other commands.
    326  *
    327  * @param cls closure
    328  * @param[out] ret result (could be anything)
    329  * @param[out] trait name of the trait
    330  * @param index index number of the object to extract.
    331  * @return #GNUNET_OK on success
    332  */
    333 static enum GNUNET_GenericReturnValue
    334 truth_store_traits (void *cls,
    335                     const void **ret,
    336                     const char *trait,
    337                     unsigned int index)
    338 {
    339   struct TruthStoreState *tss = cls;
    340   struct TALER_TESTING_Trait traits[] = {
    341     ANASTASIS_TESTING_make_trait_truth_uuid (&tss->uuid),
    342     ANASTASIS_TESTING_make_trait_truth_key (&tss->key),
    343     ANASTASIS_TESTING_make_trait_eks (&tss->encrypted_keyshare),
    344     ANASTASIS_TESTING_make_trait_payment_secret (&tss->payment_secret_response),
    345     TALER_TESTING_make_trait_taler_uri (tss->pay_uri),
    346     ANASTASIS_TESTING_make_trait_filename (tss->filename),
    347     TALER_TESTING_trait_end ()
    348   };
    349 
    350   return TALER_TESTING_get_trait (traits,
    351                                   ret,
    352                                   trait,
    353                                   index);
    354 }
    355 
    356 
    357 struct TALER_TESTING_Command
    358 ANASTASIS_TESTING_cmd_truth_store (const char *label,
    359                                    const char *anastasis_url,
    360                                    const char *prev_upload,
    361                                    const char *method,
    362                                    const char *mime_type,
    363                                    size_t truth_data_size,
    364                                    const void *truth_data,
    365                                    enum ANASTASIS_TESTING_TruthStoreOption tso,
    366                                    unsigned int http_status)
    367 {
    368   struct TruthStoreState *tss;
    369 
    370   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    371               "Storing %u bytes of truth\n",
    372               (unsigned int) truth_data_size);
    373   tss = GNUNET_new (struct TruthStoreState);
    374   tss->http_status = http_status;
    375   tss->tsopt = tso;
    376   tss->anastasis_url = anastasis_url;
    377   tss->prev_upload = prev_upload;
    378   tss->method = method;
    379   tss->mime_type = mime_type;
    380   tss->truth_data = GNUNET_memdup (truth_data,
    381                                    truth_data_size);
    382   tss->truth_data_size = truth_data_size;
    383   if (0 == strcasecmp (method,
    384                        "file"))
    385     tss->filename = GNUNET_strndup (truth_data,
    386                                     truth_data_size);
    387   {
    388     struct TALER_TESTING_Command cmd = {
    389       .cls = tss,
    390       .label = label,
    391       .run = &truth_store_run,
    392       .cleanup = &truth_store_cleanup,
    393       .traits = &truth_store_traits
    394     };
    395 
    396     return cmd;
    397   }
    398 }
    399 
    400 
    401 struct TALER_TESTING_Command
    402 ANASTASIS_TESTING_cmd_truth_question (
    403   const char *label,
    404   const char *anastasis_url,
    405   const char *prev_upload,
    406   const char *answer,
    407   enum ANASTASIS_TESTING_TruthStoreOption tso,
    408   unsigned int http_status)
    409 {
    410   struct GNUNET_HashCode h;
    411 
    412   GNUNET_CRYPTO_hash (answer,
    413                       strlen (answer),
    414                       &h);
    415   return ANASTASIS_TESTING_cmd_truth_store (label,
    416                                             anastasis_url,
    417                                             prev_upload,
    418                                             "question",
    419                                             "binary/sha512",
    420                                             sizeof (h),
    421                                             &h,
    422                                             tso,
    423                                             http_status);
    424 }