frosix

Multiparty signature service (experimental)
Log | Files | Refs | README | LICENSE

frosix_api_dkg-key_store.c (10328B)


      1 /*
      2   This file is part of ANASTASIS
      3   Copyright (C) 2014-2019 Anastasis SARL
      4 
      5   ANASTASIS is free software; you can redistribute it and/or modify
      6   it under the terms of the GNU General Public License as
      7   published by the Free Software Foundation; either version 2.1,
      8   or (at your option) any later version.
      9 
     10   ANASTASIS is distributed in the hope that it will be useful, but
     11   WITHOUT ANY WARRANTY; without even the implied warranty of
     12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13   GNU General Public License for more details.
     14 
     15   You should have received a copy of the GNU General Public
     16   License along with ANASTASIS; see the file COPYING.LGPL.  If not,
     17   see <http://www.gnu.org/licenses/>
     18 */
     19 
     20 /**
     21  * @file restclient/frosix_api_dkg-key_store.c
     22  * @brief Implementation of the /dkg-key POST
     23  * @author Christian Grothoff
     24  * @author Dennis Neufeld
     25  * @author Dominik Meister
     26  * @author Joel Urech
     27  */
     28 #include "platform.h"
     29 #include <curl/curl.h>
     30 #include <microhttpd.h> /* just for HTTP status codes */
     31 #include "frosix_service.h"
     32 #include "frost_high.h"
     33 #include "frosix_api_curl_defaults.h"
     34 #include <gnunet/gnunet_json_lib.h>
     35 #include <taler/taler_json_lib.h>
     36 
     37 
     38 /**
     39  * @brief A Contract Operation Handle
     40  */
     41 struct FROSIX_DkgKeyStoreOperation
     42 {
     43   /**
     44    * The url for this request, including parameters.
     45    */
     46   char *url;
     47 
     48   /**
     49    * FIXME
     50   */
     51   uint8_t provider_index;
     52 
     53   /**
     54    * Handle for the request.
     55    */
     56   struct GNUNET_CURL_Job *job;
     57 
     58   /**
     59    * The CURL context to connect to the backend
     60   */
     61   struct GNUNET_CURL_Context *ctx;
     62 
     63   /**
     64    * Function to call with the result.
     65    */
     66   FROSIX_DkgKeyStoreCallback cb;
     67 
     68   /**
     69    * Closure for @a cb.
     70    */
     71   void *cb_cls;
     72 };
     73 
     74 
     75 void
     76 FROSIX_dkg_key_store_cancel (
     77   struct FROSIX_DkgKeyStoreOperation *dko)
     78 {
     79   if (NULL != dko->job)
     80   {
     81     GNUNET_CURL_job_cancel (dko->job);
     82     dko->job = NULL;
     83   }
     84   GNUNET_free (dko->url);
     85   GNUNET_free (dko);
     86 }
     87 
     88 
     89 /**
     90  * Callback to process POST /dkg-key response
     91  *
     92  * @param cls the `struct FROSIX_DkgKeyStoreOperation`
     93  * @param response_code HTTP response code, 0 on error
     94  * @param data response body
     95  * @param data_size number of byte in @a data
     96 */
     97 static void
     98 handle_dkg_key_store_finished (void *cls,
     99                                long response_code,
    100                                const void *response)
    101 {
    102   struct FROSIX_DkgKeyStoreOperation *dko = cls;
    103   struct FROSIX_DkgKeyStoreDetails dkd;
    104   const json_t *json_response = response;
    105 
    106   dko->job = NULL;
    107   dkd.http_status = response_code;
    108   dkd.ec = TALER_EC_NONE;
    109 
    110   switch (response_code)
    111   {
    112   case 0:
    113     /* Hard error */
    114     GNUNET_break (0);
    115     dkd.dks = FROSIX_DKS_HTTP_ERROR;
    116     dkd.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    117     break;
    118   case MHD_HTTP_CREATED:
    119   case MHD_HTTP_OK:
    120     {
    121       dkd.dks = FROSIX_DKS_SUCCESS;
    122       dkd.provider_index = dko->provider_index;
    123 
    124       /* We got a result, lets parse it */
    125       struct GNUNET_JSON_Specification spec[] = {
    126         GNUNET_JSON_spec_fixed_auto ("public_key",
    127                                      &dkd.details.public_key),
    128         GNUNET_JSON_spec_fixed_auto ("signature",
    129                                      &dkd.details.signature),
    130         GNUNET_JSON_spec_end ()
    131       };
    132 
    133       if (GNUNET_OK !=
    134           GNUNET_JSON_parse (json_response,
    135                              spec,
    136                              NULL,
    137                              NULL))
    138       {
    139         /* Parsing failed! */
    140         GNUNET_break_op (0);
    141         dkd.http_status = 0;
    142         GNUNET_JSON_parse_free (spec);
    143         break;
    144       }
    145 
    146       GNUNET_JSON_parse_free (spec);
    147       break;
    148     }
    149   case MHD_HTTP_BAD_REQUEST:
    150     /* We have a conflict with the API */
    151     GNUNET_break (0);
    152     dkd.dks = FROSIX_DKS_CLIENT_ERROR;
    153     dkd.ec = TALER_JSON_get_error_code2 (json_response,
    154                                          json_object_size (json_response));
    155     break;
    156   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    157     /* The provider has a problem! */
    158     GNUNET_break (0);
    159     dkd.dks = FROSIX_DKS_SERVER_ERROR;
    160     dkd.ec = TALER_JSON_get_error_code2 (json_response,
    161                                          json_object_size (json_response));
    162     break;
    163   default:
    164     /* Unexpected response code */
    165     GNUNET_break (0);
    166     dkd.ec = TALER_JSON_get_error_code2 (json_response,
    167                                          json_object_size (json_response));
    168     break;
    169   }
    170 
    171   /* return to callback function with the data from the response */
    172   dko->cb (dko->cb_cls,
    173            &dkd);
    174   dko->cb = NULL;
    175 
    176   FROSIX_dkg_key_store_cancel (dko);
    177 }
    178 
    179 
    180 /**
    181  * Handle HTTP header received by curl.
    182  *
    183  * @param buffer one line of HTTP header data
    184  * @param size size of an item
    185  * @param userdata our `struct FROSIX_DkgKeyStoreOperation`
    186  * @return `size * nitems`
    187 */
    188 static size_t
    189 handle_header (char *buffer,
    190                size_t size,
    191                size_t nitems,
    192                void *userdata)
    193 {
    194   // struct FROSIX_DkgKeyStoreOperation *dko = userdata;
    195   size_t total = size * nitems;
    196   char *ndup;
    197   const char *hdr_type;
    198   char *hdr_val;
    199   char *sp;
    200 
    201   ndup = GNUNET_strndup (buffer,
    202                          total);
    203 
    204   hdr_type = strtok_r (ndup,
    205                        ":",
    206                        &sp);
    207   if (NULL == hdr_type)
    208   {
    209     GNUNET_free (ndup);
    210     return total;
    211   }
    212   hdr_val = strtok_r (NULL,
    213                       "\n\r",
    214                       &sp);
    215   if (NULL == hdr_val)
    216   {
    217     GNUNET_free (ndup);
    218     return total;
    219   }
    220   if (' ' == *hdr_val)
    221     hdr_val++;
    222   /* ... FIXME */
    223   return total;
    224 }
    225 
    226 
    227 struct FROSIX_DkgKeyStoreOperation *
    228 FROSIX_dkg_key_store (
    229   struct GNUNET_CURL_Context *ctx,
    230   const char *backend_url,
    231   const struct FROSIX_DkgRequestIdP *uuid,
    232   uint8_t identifier,
    233   uint8_t threshold,
    234   uint8_t num_of_participants,
    235   const struct FROSIX_DkgContextStringP *context_string,
    236   const struct FROSIX_ChallengeHashP *challenge_hash,
    237   const struct GNUNET_CRYPTO_EddsaPublicKey providers_public_keys[],
    238   const struct FROSIX_EncryptionKey *encryption_key,
    239   unsigned int expiration,
    240   const struct FROSIX_DkgKeyStoreShare secret_shares[],
    241   size_t len,
    242   FROSIX_DkgKeyStoreCallback cb,
    243   void *cb_cls)
    244 {
    245   struct FROSIX_DkgKeyStoreOperation *dko;
    246   CURL *eh;
    247   char *json_str;
    248 
    249   /* check if we got a callback function, abort if not */
    250   GNUNET_assert (NULL != cb);
    251 
    252   dko = GNUNET_new (struct FROSIX_DkgKeyStoreOperation);
    253 
    254   {
    255     /* prepare URL */
    256     char *uuid_str;
    257     char *path;
    258 
    259     uuid_str = GNUNET_STRINGS_data_to_string_alloc (uuid,
    260                                                     sizeof (*uuid));
    261 
    262     GNUNET_asprintf (&path,
    263                      "dkg-key/%s",
    264                      uuid_str);
    265 
    266     dko->url = TALER_url_join (backend_url,
    267                                path,
    268                                NULL);
    269 
    270     GNUNET_free (path);
    271     GNUNET_free (uuid_str);
    272   }
    273 
    274   dko->provider_index = identifier;
    275 
    276   /* array for all providers public keys */
    277   json_t *json_public_keys = json_array ();
    278 
    279   for (unsigned int i = 0; i < num_of_participants; i++)
    280   {
    281     /* single public key */
    282     json_t *public_key;
    283     public_key = GNUNET_JSON_PACK (
    284       GNUNET_JSON_pack_data_auto (NULL,
    285                                   &providers_public_keys[i]));
    286 
    287     /* add to public key array */
    288     GNUNET_assert (0 ==
    289                    json_array_append_new (
    290                      json_public_keys,
    291                      public_key));
    292   }
    293 
    294   {
    295     /* array for all secret shares */
    296     json_t *shares = json_array ();
    297 
    298     for (unsigned int i = 0; i < len; i++)
    299     {
    300       /* single secret share */
    301       json_t *share;
    302       share = GNUNET_JSON_PACK (
    303         GNUNET_JSON_pack_uint64 ("provider_index",
    304                                  secret_shares[i].identifier),
    305         GNUNET_JSON_pack_data_auto ("secret_share",
    306                                     &secret_shares[i].secret_share),
    307         GNUNET_JSON_pack_data_auto ("ephemeral_key",
    308                                     &secret_shares[i].ephemeral_key));
    309 
    310       /* add to secret shares array */
    311       GNUNET_assert (0 ==
    312                      json_array_append_new (
    313                        shares,
    314                        share));
    315     }
    316 
    317     /* pack the json object for the request body */
    318     json_t *dkg_key_data;
    319     dkg_key_data = GNUNET_JSON_PACK (
    320       GNUNET_JSON_pack_uint64 ("provider_index",
    321                                identifier),
    322       GNUNET_JSON_pack_uint64 ("threshold",
    323                                threshold),
    324       GNUNET_JSON_pack_data_auto ("context_string",
    325                                   context_string),
    326       GNUNET_JSON_pack_data_auto ("auth_hash",
    327                                   challenge_hash),
    328       GNUNET_JSON_pack_array_steal ("providers_public_keys",
    329                                     json_public_keys),
    330       GNUNET_JSON_pack_data_auto ("pre_encryption_key",
    331                                   encryption_key),
    332       GNUNET_JSON_pack_uint64 ("expiration",
    333                                expiration),
    334       GNUNET_JSON_pack_array_steal ("secret_shares",
    335                                     shares));
    336 
    337     json_str = json_dumps (dkg_key_data,
    338                            JSON_COMPACT);
    339 
    340     /* check if we have a json object, abort if it was not successful */
    341     GNUNET_assert (NULL != json_str);
    342 
    343     json_decref (dkg_key_data);
    344   }
    345 
    346   /* prepare curl options and fire the request */
    347   dko->ctx = ctx;
    348   dko->cb = cb;
    349   dko->cb_cls = cb_cls;
    350 
    351   eh = FROSIX_curl_easy_get_ (dko->url);
    352 
    353   GNUNET_assert (CURLE_OK ==
    354                  curl_easy_setopt (eh,
    355                                    CURLOPT_POSTFIELDS,
    356                                    json_str));
    357   GNUNET_assert (CURLE_OK ==
    358                  curl_easy_setopt (eh,
    359                                    CURLOPT_POSTFIELDSIZE,
    360                                    strlen (json_str)));
    361   GNUNET_assert (CURLE_OK ==
    362                  curl_easy_setopt (eh,
    363                                    CURLOPT_HEADERFUNCTION,
    364                                    &handle_header));
    365   GNUNET_assert (CURLE_OK ==
    366                  curl_easy_setopt (eh,
    367                                    CURLOPT_HEADERDATA,
    368                                    dko));
    369 
    370   dko->job = GNUNET_CURL_job_add (ctx,
    371                                   eh,
    372                                   &handle_dkg_key_store_finished,
    373                                   dko);
    374 
    375   return dko;
    376 }