frosix

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

frosix_api_dkg-share_request.c (12740B)


      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-share_request.c
     22  * @brief Implementation of the /dkg-share 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_DkgShareRequestOperation
     42 {
     43   /**
     44    * The url for this request, including parameters.
     45    */
     46   char *url;
     47 
     48   /**
     49    * Handle for the request.
     50    */
     51   struct GNUNET_CURL_Job *job;
     52 
     53   /**
     54    * Provider index
     55   */
     56   uint8_t provider_index;
     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_DkgShareRequestCallback cb;
     67 
     68   /**
     69    * Closure for @a cb.
     70    */
     71   void *cb_cls;
     72 };
     73 
     74 
     75 void
     76 FROSIX_dkg_share_request_cancel (
     77   struct FROSIX_DkgShareRequestOperation *dso)
     78 {
     79   if (NULL != dso->job)
     80   {
     81     GNUNET_CURL_job_cancel (dso->job);
     82     dso->job = NULL;
     83   }
     84   GNUNET_free (dso->url);
     85   GNUNET_free (dso);
     86 }
     87 
     88 
     89 /**
     90  * Callback to process POST /dkg-share response
     91  *
     92  * @param cls the `struct FROSIX_DkgShareRequestOperation`
     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_share_request_finished (void *cls,
     99                                    long response_code,
    100                                    const void *response)
    101 {
    102   struct FROSIX_DkgShareRequestOperation *dso = cls;
    103   struct FROSIX_DkgShareRequestDetails dsd;
    104   const json_t *json_response = response;
    105 
    106   dso->job = NULL;
    107   dsd.http_status = response_code;
    108   dsd.ec = TALER_EC_NONE;
    109 
    110   switch (response_code)
    111   {
    112   case 0:
    113     /* Hard error */
    114     GNUNET_break (0);
    115     dsd.dss = FROSIX_DSS_HTTP_ERROR;
    116     dsd.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    117     break;
    118   case MHD_HTTP_CREATED:
    119   case MHD_HTTP_OK:
    120     {
    121       dsd.dss = FROSIX_DSS_SUCCESS;
    122       dsd.provider_index = dso->provider_index;
    123 
    124       /* We got a result, lets parse it */
    125       json_t *secret_shares = NULL;
    126       struct GNUNET_JSON_Specification spec[] = {
    127         GNUNET_JSON_spec_json ("secret_shares",
    128                                &secret_shares),
    129         GNUNET_JSON_spec_end ()
    130       };
    131 
    132       if (GNUNET_OK !=
    133           GNUNET_JSON_parse (json_response,
    134                              spec,
    135                              NULL,
    136                              NULL))
    137       {
    138         /* Parsing failed! */
    139         GNUNET_break_op (0);
    140         dsd.http_status = 0;
    141         GNUNET_JSON_parse_free (spec);
    142         break;
    143       }
    144 
    145       /* check if size of array is in allowed range */
    146       if (0 >= json_array_size (secret_shares)
    147           || json_array_size (secret_shares) >= 254)
    148       {
    149         GNUNET_break_op (0);
    150         dsd.http_status = 0;
    151         GNUNET_JSON_parse_free (spec);
    152         break;
    153       }
    154 
    155       dsd.shares_len = json_array_size (secret_shares);
    156 
    157       /* allocate memory */
    158       dsd.shares = GNUNET_malloc (dsd.shares_len * sizeof (*dsd.shares));
    159       GNUNET_assert (NULL != dsd.shares);
    160 
    161       for (unsigned int i = 0; i < dsd.shares_len; i++)
    162       {
    163         struct GNUNET_JSON_Specification share_spec[] = {
    164           GNUNET_JSON_spec_uint8 ("target",
    165                                   &dsd.shares[i].target),
    166           GNUNET_JSON_spec_uint8 ("issuer",
    167                                   &dsd.shares[i].issuer),
    168           GNUNET_JSON_spec_fixed_auto ("secret_share",
    169                                        &dsd.shares[i].encrypted_share),
    170           GNUNET_JSON_spec_fixed_auto ("ephemeral_key",
    171                                        &dsd.shares[i].ephemeral_key),
    172           GNUNET_JSON_spec_end ()
    173         };
    174 
    175         if (GNUNET_OK !=
    176             GNUNET_JSON_parse (json_array_get (secret_shares,
    177                                                i),
    178                                share_spec,
    179                                NULL,
    180                                NULL))
    181         {
    182           GNUNET_break_op (0);
    183           GNUNET_JSON_parse_free (share_spec);
    184           GNUNET_JSON_parse_free (spec);
    185           dsd.http_status = 0;
    186           break;
    187         }
    188 
    189         GNUNET_JSON_parse_free (share_spec);
    190       }
    191 
    192       GNUNET_JSON_parse_free (spec);
    193 
    194       break;
    195     }
    196   case MHD_HTTP_BAD_REQUEST:
    197     /* We have a conflict with the API */
    198     GNUNET_break (0);
    199     dsd.dss = FROSIX_DSS_CLIENT_ERROR;
    200     dsd.ec = TALER_JSON_get_error_code2 (json_response,
    201                                          json_object_size (json_response));
    202     break;
    203   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    204     /* The provider has a problem! */
    205     GNUNET_break (0);
    206     dsd.dss = FROSIX_DSS_SERVER_ERROR;
    207     dsd.ec = TALER_JSON_get_error_code2 (json_response,
    208                                          json_object_size (json_response));
    209     break;
    210   default:
    211     /* Unexpected response code */
    212     GNUNET_break (0);
    213     dsd.ec = TALER_JSON_get_error_code2 (json_response,
    214                                          json_object_size (json_response));
    215     break;
    216   }
    217 
    218   /* return to callback function with the data from the response */
    219   dso->cb (dso->cb_cls,
    220            &dsd);
    221   dso->cb = NULL;
    222 
    223   FROSIX_dkg_share_request_cancel (dso);
    224 }
    225 
    226 
    227 /**
    228  * Handle HTTP header received by curl.
    229  *
    230  * @param buffer one line of HTTP header data
    231  * @param size size of an item
    232  * @param userdata our `struct FROSIX_DkgShareRequestOperation`
    233  * @return `size * nitems`
    234 */
    235 static size_t
    236 handle_header (char *buffer,
    237                size_t size,
    238                size_t nitems,
    239                void *userdata)
    240 {
    241   // struct FROSIX_DkgShareRequestOperation *dso = userdata;
    242   size_t total = size * nitems;
    243   char *ndup;
    244   const char *hdr_type;
    245   char *hdr_val;
    246   char *sp;
    247 
    248   ndup = GNUNET_strndup (buffer,
    249                          total);
    250 
    251   hdr_type = strtok_r (ndup,
    252                        ":",
    253                        &sp);
    254   if (NULL == hdr_type)
    255   {
    256     GNUNET_free (ndup);
    257     return total;
    258   }
    259   hdr_val = strtok_r (NULL,
    260                       "\n\r",
    261                       &sp);
    262   if (NULL == hdr_val)
    263   {
    264     GNUNET_free (ndup);
    265     return total;
    266   }
    267   if (' ' == *hdr_val)
    268     hdr_val++;
    269   /* ... FIXME */
    270   return total;
    271 }
    272 
    273 
    274 struct FROSIX_DkgShareRequestOperation *
    275 FROSIX_dkg_share_request (
    276   struct GNUNET_CURL_Context *ctx,
    277   const char *backend_url,
    278   const struct FROSIX_DkgRequestIdP *uuid,
    279   uint8_t identifier,
    280   uint8_t threshold,
    281   uint8_t num_of_participants,
    282   const struct FROSIX_DkgContextStringP *context_string,
    283   const struct FROSIX_ChallengeHashP *challenge_hash,
    284   const struct FROSIX_DkgCommitment dkg_commitments[],
    285   size_t len,
    286   const struct GNUNET_CRYPTO_EddsaPublicKey providers_public_keys[],
    287   FROSIX_DkgShareRequestCallback cb,
    288   void *cb_cls)
    289 {
    290   struct FROSIX_DkgShareRequestOperation *dso;
    291   CURL *eh;
    292   char *json_str;
    293 
    294   /* check if we got a callback function, abort if not */
    295   GNUNET_assert (NULL != cb);
    296 
    297   dso = GNUNET_new (struct FROSIX_DkgShareRequestOperation);
    298 
    299   {
    300     /* prepare URL */
    301     char *uuid_str;
    302     char *path;
    303 
    304     uuid_str = GNUNET_STRINGS_data_to_string_alloc (uuid,
    305                                                     sizeof (*uuid));
    306 
    307     GNUNET_asprintf (&path,
    308                      "dkg-shares/%s",
    309                      uuid_str);
    310 
    311     dso->url = TALER_url_join (backend_url,
    312                                path,
    313                                NULL);
    314 
    315     GNUNET_free (path);
    316     GNUNET_free (uuid_str);
    317   }
    318 
    319   dso->provider_index = identifier;
    320 
    321   /* array for all providers public keys */
    322   json_t *json_public_keys = json_array ();
    323 
    324   for (unsigned int i = 0; i < num_of_participants; i++)
    325   {
    326     /* single public key */
    327     json_t *public_key;
    328     public_key = GNUNET_JSON_PACK (
    329       GNUNET_JSON_pack_data_auto (NULL,
    330                                   &providers_public_keys[i]));
    331 
    332     /* add to public key array */
    333     GNUNET_assert (0 ==
    334                    json_array_append_new (
    335                      json_public_keys,
    336                      public_key));
    337   }
    338 
    339   {
    340     /* array for all dkg commitments */
    341     json_t *commitments = json_array ();
    342 
    343     for (unsigned int i = 0; i < len; i++)
    344     {
    345       /* dkg commitment values */
    346       json_t *commitment_values = json_array ();
    347       for (unsigned int j = 0;
    348            j < dkg_commitments[i].commitment.shares_commitments_length;
    349            j++)
    350       {
    351         /* single commitment value */
    352         json_t *temp_value = json_object ();
    353         temp_value = GNUNET_JSON_PACK (
    354           GNUNET_JSON_pack_data_auto (
    355             NULL,
    356             &dkg_commitments[i].commitment.share_comm[j]));
    357 
    358         /* add to commitment_values array */
    359         GNUNET_assert (0 ==
    360                        json_array_append_new (
    361                          commitment_values,
    362                          temp_value));
    363       }
    364 
    365       /* single dkg commitment */
    366       json_t *dkg_commitment;
    367       dkg_commitment = GNUNET_JSON_PACK (
    368         GNUNET_JSON_pack_uint64 ("provider_index",
    369                                  dkg_commitments[i].commitment.identifier),
    370         GNUNET_JSON_pack_array_steal ("dkg_commitment",
    371                                       commitment_values),
    372         GNUNET_JSON_pack_data_auto ("zkp_r",
    373                                     &dkg_commitments[i].commitment.zkp.r),
    374         GNUNET_JSON_pack_data_auto ("zkp_z",
    375                                     &dkg_commitments[i].commitment.zkp.z),
    376         GNUNET_JSON_pack_data_auto ("public_key",
    377                                     &dkg_commitments[i].encryption_public_key));
    378 
    379       /* add to commitments array */
    380       GNUNET_assert (0 ==
    381                      json_array_append_new (
    382                        commitments,
    383                        dkg_commitment));
    384     }
    385 
    386     /* pack the json object for the request body */
    387     json_t *dkg_share_data;
    388     dkg_share_data = GNUNET_JSON_PACK (
    389       GNUNET_JSON_pack_uint64 ("provider_index",
    390                                identifier),
    391       GNUNET_JSON_pack_uint64 ("threshold",
    392                                threshold),
    393       GNUNET_JSON_pack_uint64 ("num_of_participants",
    394                                num_of_participants),
    395       GNUNET_JSON_pack_data_auto ("context_string",
    396                                   context_string),
    397       GNUNET_JSON_pack_data_auto ("auth_hash",
    398                                   challenge_hash),
    399       GNUNET_JSON_pack_array_steal ("providers_public_keys",
    400                                     json_public_keys),
    401       GNUNET_JSON_pack_array_steal ("dkg_commitments",
    402                                     commitments));
    403 
    404     json_str = json_dumps (dkg_share_data,
    405                            JSON_COMPACT);
    406 
    407     /* check if we have a json object, abort if it was not successful */
    408     GNUNET_assert (NULL != json_str);
    409 
    410     json_decref (dkg_share_data);
    411   }
    412 
    413   /* prepare curl options and fire the request */
    414   dso->ctx = ctx;
    415   dso->cb = cb;
    416   dso->cb_cls = cb_cls;
    417 
    418   eh = FROSIX_curl_easy_get_ (dso->url);
    419 
    420   GNUNET_assert (CURLE_OK ==
    421                  curl_easy_setopt (eh,
    422                                    CURLOPT_POSTFIELDS,
    423                                    json_str));
    424   GNUNET_assert (CURLE_OK ==
    425                  curl_easy_setopt (eh,
    426                                    CURLOPT_POSTFIELDSIZE,
    427                                    strlen (json_str)));
    428   GNUNET_assert (CURLE_OK ==
    429                  curl_easy_setopt (eh,
    430                                    CURLOPT_HEADERFUNCTION,
    431                                    &handle_header));
    432   GNUNET_assert (CURLE_OK ==
    433                  curl_easy_setopt (eh,
    434                                    CURLOPT_HEADERDATA,
    435                                    dso));
    436 
    437   dso->job = GNUNET_CURL_job_add (ctx,
    438                                   eh,
    439                                   &handle_dkg_share_request_finished,
    440                                   dso);
    441 
    442   return dso;
    443 }