anastasis

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

testing_api_cmd_truth_store.c (11498B)


      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 #include "anastasis_testing_lib.h"
     23 #include <taler/taler_util.h>
     24 #include <taler/taler_testing_lib.h>
     25 #include <taler/taler_merchant_service.h>
     26 
     27 /**
     28  * State for a "truth store" CMD.
     29  */
     30 struct TruthStoreState
     31 {
     32   /**
     33    * UUID of the uploaded truth
     34    */
     35   struct ANASTASIS_CRYPTO_TruthUUIDP uuid;
     36 
     37   /**
     38    * Key used to encrypt the @e truth_data on the server.
     39    */
     40   struct ANASTASIS_CRYPTO_TruthKeyP key;
     41 
     42   /**
     43    * "Encrypted" key share data we store at the server.
     44    */
     45   struct ANASTASIS_CRYPTO_EncryptedKeyShareP encrypted_keyshare;
     46 
     47   /**
     48    * The /truth POST operation handle.
     49    */
     50   struct ANASTASIS_TruthStoreOperation *tso;
     51 
     52   /**
     53    * URL of the anastasis backend.
     54    */
     55   const char *anastasis_url;
     56 
     57   /**
     58    * The interpreter state.
     59    */
     60   struct TALER_TESTING_Interpreter *is;
     61 
     62   /**
     63    * Previous upload, or NULL for none. Used to calculate what THIS
     64    * upload is based on.
     65    */
     66   const char *prev_upload;
     67 
     68   /**
     69    * Authorization method / plugin name.
     70    */
     71   const char *method;
     72 
     73   /**
     74    * Mimetype of @e truth_data.
     75    */
     76   const char *mime_type;
     77 
     78   /**
     79    * Number of bytes in @e truth_data
     80    */
     81   size_t truth_data_size;
     82 
     83   /**
     84    * Data used by the authorization process.
     85    */
     86   void *truth_data;
     87 
     88   /**
     89    * Name of the file where the service will write the challenge, or NULL.
     90    */
     91   char *filename;
     92 
     93   /**
     94    * Expected status code.
     95    */
     96   unsigned int http_status;
     97 
     98   /**
     99    * Payment request we got back, or NULL.
    100    */
    101   char *pay_uri;
    102 
    103   /**
    104    * Payment order ID we got back, or all zeros.
    105    */
    106   struct ANASTASIS_PaymentSecretP payment_secret_response;
    107 
    108   /**
    109    * Options for how we are supposed to do the upload.
    110    */
    111   enum ANASTASIS_TESTING_TruthStoreOption tsopt;
    112 };
    113 
    114 /**
    115  * Function called with the results of an #ANASTASIS_truth_store()
    116  * operation.
    117  *
    118  * @param cls closure
    119  * @param ud details about the upload operation
    120  */
    121 static void
    122 truth_store_cb (void *cls,
    123                 const struct ANASTASIS_UploadDetails *ud)
    124 {
    125   struct TruthStoreState *tss = cls;
    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       ANASTASIS_CRYPTO_truth_decrypt (&tss->key,
    251                                       encrypted_truth,
    252                                       size_encrypted_truth,
    253                                       &t,
    254                                       &t_size);
    255       if ( (t_size != tss->truth_data_size) ||
    256            (0 != memcmp (tss->truth_data,
    257                          t,
    258                          t_size)) )
    259       {
    260         GNUNET_break (0);
    261         TALER_TESTING_interpreter_fail (tss->is);
    262         return;
    263       }
    264       GNUNET_free (t);
    265     }
    266     tss->tso = ANASTASIS_truth_store (
    267       TALER_TESTING_interpreter_get_context (is),
    268       tss->anastasis_url,
    269       &tss->uuid,
    270       tss->method,
    271       &tss->encrypted_keyshare,
    272       tss->mime_type,
    273       size_encrypted_truth,
    274       encrypted_truth,
    275       (0 != (ANASTASIS_TESTING_TSO_REQUEST_PAYMENT & tss->tsopt)),
    276       GNUNET_TIME_UNIT_ZERO,
    277       &truth_store_cb,
    278       tss);
    279     GNUNET_free (encrypted_truth);
    280   }
    281   if (NULL == tss->tso)
    282   {
    283     GNUNET_break (0);
    284     TALER_TESTING_interpreter_fail (tss->is);
    285     return;
    286   }
    287 }
    288 
    289 
    290 /**
    291  * Free the state of a "truth store" CMD, and possibly
    292  * cancel it if it did not complete.
    293  *
    294  * @param cls closure.
    295  * @param cmd command being freed.
    296  */
    297 static void
    298 truth_store_cleanup (void *cls,
    299                      const struct TALER_TESTING_Command *cmd)
    300 {
    301   struct TruthStoreState *tss = cls;
    302 
    303   if (NULL != tss->tso)
    304   {
    305     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    306                 "Command '%s' did not complete (truth post)\n",
    307                 cmd->label);
    308     ANASTASIS_truth_store_cancel (tss->tso);
    309     tss->tso = NULL;
    310   }
    311   GNUNET_free (tss->truth_data);
    312   GNUNET_free (tss->pay_uri);
    313   GNUNET_free (tss->filename);
    314   GNUNET_free (tss);
    315 }
    316 
    317 
    318 /**
    319  * Offer internal data to other commands.
    320  *
    321  * @param cls closure
    322  * @param[out] ret result (could be anything)
    323  * @param[out] trait name of the trait
    324  * @param index index number of the object to extract.
    325  * @return #GNUNET_OK on success
    326  */
    327 static enum GNUNET_GenericReturnValue
    328 truth_store_traits (void *cls,
    329                     const void **ret,
    330                     const char *trait,
    331                     unsigned int index)
    332 {
    333   struct TruthStoreState *tss = cls;
    334   struct TALER_TESTING_Trait traits[] = {
    335     ANASTASIS_TESTING_make_trait_truth_uuid (&tss->uuid),
    336     ANASTASIS_TESTING_make_trait_truth_key (&tss->key),
    337     ANASTASIS_TESTING_make_trait_eks (&tss->encrypted_keyshare),
    338     ANASTASIS_TESTING_make_trait_payment_secret (&tss->payment_secret_response),
    339     TALER_TESTING_make_trait_taler_uri (tss->pay_uri),
    340     ANASTASIS_TESTING_make_trait_filename (tss->filename),
    341     TALER_TESTING_trait_end ()
    342   };
    343 
    344   return TALER_TESTING_get_trait (traits,
    345                                   ret,
    346                                   trait,
    347                                   index);
    348 }
    349 
    350 
    351 struct TALER_TESTING_Command
    352 ANASTASIS_TESTING_cmd_truth_store (const char *label,
    353                                    const char *anastasis_url,
    354                                    const char *prev_upload,
    355                                    const char *method,
    356                                    const char *mime_type,
    357                                    size_t truth_data_size,
    358                                    const void *truth_data,
    359                                    enum ANASTASIS_TESTING_TruthStoreOption tso,
    360                                    unsigned int http_status)
    361 {
    362   struct TruthStoreState *tss;
    363 
    364   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    365               "Storing %u bytes of truth\n",
    366               (unsigned int) truth_data_size);
    367   tss = GNUNET_new (struct TruthStoreState);
    368   tss->http_status = http_status;
    369   tss->tsopt = tso;
    370   tss->anastasis_url = anastasis_url;
    371   tss->prev_upload = prev_upload;
    372   tss->method = method;
    373   tss->mime_type = mime_type;
    374   tss->truth_data = GNUNET_memdup (truth_data,
    375                                    truth_data_size);
    376   tss->truth_data_size = truth_data_size;
    377   if (0 == strcasecmp (method,
    378                        "file"))
    379     tss->filename = GNUNET_strndup (truth_data,
    380                                     truth_data_size);
    381   {
    382     struct TALER_TESTING_Command cmd = {
    383       .cls = tss,
    384       .label = label,
    385       .run = &truth_store_run,
    386       .cleanup = &truth_store_cleanup,
    387       .traits = &truth_store_traits
    388     };
    389 
    390     return cmd;
    391   }
    392 }
    393 
    394 
    395 struct TALER_TESTING_Command
    396 ANASTASIS_TESTING_cmd_truth_question (
    397   const char *label,
    398   const char *anastasis_url,
    399   const char *prev_upload,
    400   const char *answer,
    401   enum ANASTASIS_TESTING_TruthStoreOption tso,
    402   unsigned int http_status)
    403 {
    404   struct GNUNET_HashCode h;
    405 
    406   GNUNET_CRYPTO_hash (answer,
    407                       strlen (answer),
    408                       &h);
    409   return ANASTASIS_TESTING_cmd_truth_store (label,
    410                                             anastasis_url,
    411                                             prev_upload,
    412                                             "question",
    413                                             "binary/sha512",
    414                                             sizeof (h),
    415                                             &h,
    416                                             tso,
    417                                             http_status);
    418 }