frosix

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

frosix_api_sig-share_request.c (9452B)


      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_sig-share_request.c
     22  * @brief Implementation of the /sig-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_SigShareRequestOperation
     42 {
     43   /**
     44    * The url for this request, including parameters.
     45    */
     46   char *url;
     47 
     48   /**
     49    * Position in the array.
     50   */
     51   uint8_t array_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_SigShareRequestCallback cb;
     67 
     68   /**
     69    * Closure for @a cb.
     70    */
     71   void *cb_cls;
     72 
     73   /**
     74    * Identifier of the provider
     75   */
     76   uint8_t provider_index;
     77 };
     78 
     79 
     80 void
     81 FROSIX_sig_share_request_cancel (
     82   struct FROSIX_SigShareRequestOperation *sso)
     83 {
     84   if (NULL != sso->job)
     85   {
     86     GNUNET_CURL_job_cancel (sso->job);
     87     sso->job = NULL;
     88   }
     89   GNUNET_free (sso->url);
     90   GNUNET_free (sso);
     91 }
     92 
     93 
     94 /**
     95  * Callback to process POST /sig-share response
     96  *
     97  * @param cls the `struct FROSIX_SigShareRequestOperation`
     98  * @param response_code HTTP response code, 0 on error
     99  * @param data response body
    100  * @param data_size number of byte in @a data
    101 */
    102 static void
    103 handle_sig_share_request_finished (void *cls,
    104                                    long response_code,
    105                                    const void *response)
    106 {
    107   struct FROSIX_SigShareRequestOperation *sso = cls;
    108   struct FROSIX_SigShareRequestDetails ssd;
    109   const json_t *json_response = response;
    110 
    111   sso->job = NULL;
    112   ssd.http_status = response_code;
    113   ssd.ec = TALER_EC_NONE;
    114   ssd.array_index = sso->array_index;
    115   ssd.sig_share.identifier = sso->provider_index;
    116 
    117   switch (response_code)
    118   {
    119   case 0:
    120     /* Hard error */
    121     GNUNET_break (0);
    122     ssd.sss = FROSIX_SSS_HTTP_ERROR;
    123     ssd.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
    124     break;
    125   case MHD_HTTP_CREATED:
    126   case MHD_HTTP_OK:
    127     {
    128       ssd.sss = FROSIX_SSS_SUCCESS;
    129 
    130       /* We got a result, lets parse it */
    131       struct GNUNET_JSON_Specification spec[] = {
    132         GNUNET_JSON_spec_fixed_auto ("signature_share",
    133                                      &ssd.sig_share.sig_share),
    134         GNUNET_JSON_spec_fixed_auto ("public_key_share",
    135                                      &ssd.sig_share.pk_i),
    136         GNUNET_JSON_spec_end ()
    137       };
    138 
    139       if (GNUNET_OK !=
    140           GNUNET_JSON_parse (json_response,
    141                              spec,
    142                              NULL,
    143                              NULL))
    144       {
    145         /* Parsing failed! */
    146         GNUNET_break_op (0);
    147         ssd.http_status = 0;
    148         GNUNET_JSON_parse_free (spec);
    149         break;
    150       }
    151 
    152       GNUNET_JSON_parse_free (spec);
    153       break;
    154     }
    155   case MHD_HTTP_BAD_REQUEST:
    156     /* We have a conflict with the API */
    157     GNUNET_break (0);
    158     ssd.sss = FROSIX_SSS_CLIENT_ERROR;
    159     ssd.ec = TALER_JSON_get_error_code2 (json_response,
    160                                          json_object_size (json_response));
    161     break;
    162   case MHD_HTTP_INTERNAL_SERVER_ERROR:
    163     /* The provider has a problem! */
    164     GNUNET_break (0);
    165     ssd.sss = FROSIX_SSS_SERVER_ERROR;
    166     ssd.ec = TALER_JSON_get_error_code2 (json_response,
    167                                          json_object_size (json_response));
    168     break;
    169   default:
    170     /* Unexpected response code */
    171     GNUNET_break (0);
    172     ssd.ec = TALER_JSON_get_error_code2 (json_response,
    173                                          json_object_size (json_response));
    174     break;
    175   }
    176 
    177   /* return to callback function with the data from the response */
    178   sso->cb (sso->cb_cls,
    179            &ssd);
    180   sso->cb = NULL;
    181 
    182   FROSIX_sig_share_request_cancel (sso);
    183   return;
    184 }
    185 
    186 
    187 /**
    188  * Handle HTTP header received by curl.
    189  *
    190  * @param buffer one line of HTTP header data
    191  * @param size size of an item
    192  * @param userdata our `struct FROSIX_SigShareRequestOperation`
    193  * @return `size * nitems`
    194 */
    195 static size_t
    196 handle_header (char *buffer,
    197                size_t size,
    198                size_t nitems,
    199                void *userdata)
    200 {
    201   // struct FROSIX_SigShareRequestOperation *sso = userdata;
    202   size_t total = size * nitems;
    203   char *ndup;
    204   const char *hdr_type;
    205   char *hdr_val;
    206   char *sp;
    207 
    208   ndup = GNUNET_strndup (buffer,
    209                          total);
    210 
    211   hdr_type = strtok_r (ndup,
    212                        ":",
    213                        &sp);
    214   if (NULL == hdr_type)
    215   {
    216     GNUNET_free (ndup);
    217     return total;
    218   }
    219   hdr_val = strtok_r (NULL,
    220                       "\n\r",
    221                       &sp);
    222   if (NULL == hdr_val)
    223   {
    224     GNUNET_free (ndup);
    225     return total;
    226   }
    227   if (' ' == *hdr_val)
    228     hdr_val++;
    229   /* ... FIXME */
    230   return total;
    231 }
    232 
    233 
    234 struct FROSIX_SigShareRequestOperation *
    235 FROSIX_sig_share_request (
    236   struct GNUNET_CURL_Context *ctx,
    237   const char *backend_url,
    238   const struct FROSIX_SigRequestIdP *uuid,
    239   uint8_t provider_index,
    240   uint8_t array_index,
    241   const struct FROSIX_EncryptionKey *encryption_key,
    242   const struct FROST_MessageHash *message_hash,
    243   const struct FROST_Commitment commitments[],
    244   size_t len,
    245   FROSIX_SigShareRequestCallback cb,
    246   void *cb_cls)
    247 {
    248   struct FROSIX_SigShareRequestOperation *sso;
    249   CURL *eh;
    250   char *json_str;
    251 
    252   /* check if we got a callback function, abort if not */
    253   GNUNET_assert (NULL != cb);
    254 
    255   sso = GNUNET_new (struct FROSIX_SigShareRequestOperation);
    256   sso->array_index = array_index;
    257   sso->provider_index = provider_index;
    258 
    259   {
    260     /* prepare URL */
    261     char *uuid_str;
    262     char *path;
    263 
    264     uuid_str = GNUNET_STRINGS_data_to_string_alloc (uuid,
    265                                                     sizeof (*uuid));
    266 
    267     GNUNET_asprintf (&path,
    268                      "sig-share/%s",
    269                      uuid_str);
    270 
    271     sso->url = TALER_url_join (backend_url,
    272                                path,
    273                                NULL);
    274 
    275     GNUNET_free (path);
    276     GNUNET_free (uuid_str);
    277   }
    278 
    279   {
    280     /* array for all packed commitments */
    281     json_t *commits = json_array ();
    282 
    283     for (unsigned int i = 0; i < len; i++)
    284     {
    285       /* single commitment */
    286       json_t *commit;
    287       commit = GNUNET_JSON_PACK (
    288         GNUNET_JSON_pack_uint64 ("identifier",
    289                                  commitments[i].identifier),
    290         GNUNET_JSON_pack_data_auto ("hiding_commitment",
    291                                     &commitments[i].hiding_commitment),
    292         GNUNET_JSON_pack_data_auto ("binding_commitment",
    293                                     &commitments[i].binding_commitment));
    294 
    295       /* add to commitments array */
    296       GNUNET_assert (0 ==
    297                      json_array_append_new (
    298                        commits,
    299                        commit));
    300     }
    301 
    302     {
    303       /* pack the json object for the request body */
    304       json_t *sig_share_data;
    305       sig_share_data = GNUNET_JSON_PACK (
    306         GNUNET_JSON_pack_data_auto ("encryption_key",
    307                                     encryption_key),
    308         GNUNET_JSON_pack_data_auto ("message_hash",
    309                                     message_hash),
    310         GNUNET_JSON_pack_array_steal ("commitments",
    311                                       commits));
    312 
    313       json_str = json_dumps (sig_share_data,
    314                              JSON_COMPACT);
    315 
    316       /* check if we have a json object, abort if it was not successful */
    317       GNUNET_assert (NULL != json_str);
    318 
    319       json_decref (sig_share_data);
    320     }
    321   }
    322 
    323   /* prepare curl options and fire the request */
    324   sso->ctx = ctx;
    325   sso->cb = cb;
    326   sso->cb_cls = cb_cls;
    327 
    328   eh = FROSIX_curl_easy_get_ (sso->url);
    329 
    330   GNUNET_assert (CURLE_OK ==
    331                  curl_easy_setopt (eh,
    332                                    CURLOPT_POSTFIELDS,
    333                                    json_str));
    334   GNUNET_assert (CURLE_OK ==
    335                  curl_easy_setopt (eh,
    336                                    CURLOPT_POSTFIELDSIZE,
    337                                    strlen (json_str)));
    338   GNUNET_assert (CURLE_OK ==
    339                  curl_easy_setopt (eh,
    340                                    CURLOPT_HEADERFUNCTION,
    341                                    &handle_header));
    342   GNUNET_assert (CURLE_OK ==
    343                  curl_easy_setopt (eh,
    344                                    CURLOPT_HEADERDATA,
    345                                    sso));
    346 
    347   sso->job = GNUNET_CURL_job_add (ctx,
    348                                   eh,
    349                                   &handle_sig_share_request_finished,
    350                                   sso);
    351 
    352   return sso;
    353 }