anastasis

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

testing_api_cmd_truth_store.c (11686B)


      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 (GNUNET_CRYPTO_QUALITY_NONCE,
    224                                 &tss->uuid,
    225                                 sizeof (struct ANASTASIS_CRYPTO_TruthUUIDP));
    226     GNUNET_CRYPTO_random_block (
    227       GNUNET_CRYPTO_QUALITY_WEAK,
    228       &tss->encrypted_keyshare,
    229       sizeof (struct ANASTASIS_CRYPTO_EncryptedKeyShareP));
    230   }
    231   GNUNET_CRYPTO_random_block (
    232     GNUNET_CRYPTO_QUALITY_WEAK,
    233     &tss->key,
    234     sizeof (struct ANASTASIS_CRYPTO_TruthKeyP));
    235 
    236   {
    237     void *encrypted_truth;
    238     size_t size_encrypted_truth;
    239     struct ANASTASIS_CRYPTO_NonceP nonce;
    240 
    241     GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
    242                                 &nonce,
    243                                 sizeof (nonce));
    244     ANASTASIS_CRYPTO_truth_encrypt (&nonce,
    245                                     &tss->key,
    246                                     tss->truth_data,
    247                                     tss->truth_data_size,
    248                                     &encrypted_truth,
    249                                     &size_encrypted_truth);
    250     {
    251       void *t;
    252       size_t t_size;
    253 
    254       ANASTASIS_CRYPTO_truth_decrypt (&tss->key,
    255                                       encrypted_truth,
    256                                       size_encrypted_truth,
    257                                       &t,
    258                                       &t_size);
    259       if ( (t_size != tss->truth_data_size) ||
    260            (0 != memcmp (tss->truth_data,
    261                          t,
    262                          t_size)) )
    263       {
    264         GNUNET_break (0);
    265         TALER_TESTING_interpreter_fail (tss->is);
    266         return;
    267       }
    268       GNUNET_free (t);
    269     }
    270     tss->tso = ANASTASIS_truth_store (
    271       TALER_TESTING_interpreter_get_context (is),
    272       tss->anastasis_url,
    273       &tss->uuid,
    274       tss->method,
    275       &tss->encrypted_keyshare,
    276       tss->mime_type,
    277       size_encrypted_truth,
    278       encrypted_truth,
    279       (0 != (ANASTASIS_TESTING_TSO_REQUEST_PAYMENT & tss->tsopt)),
    280       GNUNET_TIME_UNIT_ZERO,
    281       &truth_store_cb,
    282       tss);
    283     GNUNET_free (encrypted_truth);
    284   }
    285   if (NULL == tss->tso)
    286   {
    287     GNUNET_break (0);
    288     TALER_TESTING_interpreter_fail (tss->is);
    289     return;
    290   }
    291 }
    292 
    293 
    294 /**
    295  * Free the state of a "truth store" CMD, and possibly
    296  * cancel it if it did not complete.
    297  *
    298  * @param cls closure.
    299  * @param cmd command being freed.
    300  */
    301 static void
    302 truth_store_cleanup (void *cls,
    303                      const struct TALER_TESTING_Command *cmd)
    304 {
    305   struct TruthStoreState *tss = cls;
    306 
    307   if (NULL != tss->tso)
    308   {
    309     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    310                 "Command '%s' did not complete (truth post)\n",
    311                 cmd->label);
    312     ANASTASIS_truth_store_cancel (tss->tso);
    313     tss->tso = NULL;
    314   }
    315   GNUNET_free (tss->truth_data);
    316   GNUNET_free (tss->pay_uri);
    317   GNUNET_free (tss->filename);
    318   GNUNET_free (tss);
    319 }
    320 
    321 
    322 /**
    323  * Offer internal data to other commands.
    324  *
    325  * @param cls closure
    326  * @param[out] ret result (could be anything)
    327  * @param[out] trait name of the trait
    328  * @param index index number of the object to extract.
    329  * @return #GNUNET_OK on success
    330  */
    331 static enum GNUNET_GenericReturnValue
    332 truth_store_traits (void *cls,
    333                     const void **ret,
    334                     const char *trait,
    335                     unsigned int index)
    336 {
    337   struct TruthStoreState *tss = cls;
    338   struct TALER_TESTING_Trait traits[] = {
    339     ANASTASIS_TESTING_make_trait_truth_uuid (&tss->uuid),
    340     ANASTASIS_TESTING_make_trait_truth_key (&tss->key),
    341     ANASTASIS_TESTING_make_trait_eks (&tss->encrypted_keyshare),
    342     ANASTASIS_TESTING_make_trait_payment_secret (&tss->payment_secret_response),
    343     TALER_TESTING_make_trait_taler_uri (tss->pay_uri),
    344     ANASTASIS_TESTING_make_trait_filename (tss->filename),
    345     TALER_TESTING_trait_end ()
    346   };
    347 
    348   return TALER_TESTING_get_trait (traits,
    349                                   ret,
    350                                   trait,
    351                                   index);
    352 }
    353 
    354 
    355 struct TALER_TESTING_Command
    356 ANASTASIS_TESTING_cmd_truth_store (const char *label,
    357                                    const char *anastasis_url,
    358                                    const char *prev_upload,
    359                                    const char *method,
    360                                    const char *mime_type,
    361                                    size_t truth_data_size,
    362                                    const void *truth_data,
    363                                    enum ANASTASIS_TESTING_TruthStoreOption tso,
    364                                    unsigned int http_status)
    365 {
    366   struct TruthStoreState *tss;
    367 
    368   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    369               "Storing %u bytes of truth\n",
    370               (unsigned int) truth_data_size);
    371   tss = GNUNET_new (struct TruthStoreState);
    372   tss->http_status = http_status;
    373   tss->tsopt = tso;
    374   tss->anastasis_url = anastasis_url;
    375   tss->prev_upload = prev_upload;
    376   tss->method = method;
    377   tss->mime_type = mime_type;
    378   tss->truth_data = GNUNET_memdup (truth_data,
    379                                    truth_data_size);
    380   tss->truth_data_size = truth_data_size;
    381   if (0 == strcasecmp (method,
    382                        "file"))
    383     tss->filename = GNUNET_strndup (truth_data,
    384                                     truth_data_size);
    385   {
    386     struct TALER_TESTING_Command cmd = {
    387       .cls = tss,
    388       .label = label,
    389       .run = &truth_store_run,
    390       .cleanup = &truth_store_cleanup,
    391       .traits = &truth_store_traits
    392     };
    393 
    394     return cmd;
    395   }
    396 }
    397 
    398 
    399 struct TALER_TESTING_Command
    400 ANASTASIS_TESTING_cmd_truth_question (
    401   const char *label,
    402   const char *anastasis_url,
    403   const char *prev_upload,
    404   const char *answer,
    405   enum ANASTASIS_TESTING_TruthStoreOption tso,
    406   unsigned int http_status)
    407 {
    408   struct GNUNET_HashCode h;
    409 
    410   GNUNET_CRYPTO_hash (answer,
    411                       strlen (answer),
    412                       &h);
    413   return ANASTASIS_TESTING_cmd_truth_store (label,
    414                                             anastasis_url,
    415                                             prev_upload,
    416                                             "question",
    417                                             "binary/sha512",
    418                                             sizeof (h),
    419                                             &h,
    420                                             tso,
    421                                             http_status);
    422 }