frosix_api_dkg-commitment_request.c (11131B)
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-commitment_request.c 22 * @brief Implementation of the /dkg-commitment 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 commitment request operation handle 40 */ 41 struct FROSIX_DkgCommitmentRequestOperation 42 { 43 /** 44 * The url for this request, including parameters. 45 */ 46 char *url; 47 48 /** 49 * 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_DkgCommitmentRequestCallback cb; 67 68 /** 69 * Closure for @a cb. 70 */ 71 void *cb_cls; 72 }; 73 74 75 void 76 FROSIX_dkg_commitment_request_cancel ( 77 struct FROSIX_DkgCommitmentRequestOperation *dco) 78 { 79 if (NULL != dco->job) 80 { 81 GNUNET_CURL_job_cancel (dco->job); 82 dco->job = NULL; 83 } 84 GNUNET_free (dco->url); 85 GNUNET_free (dco); 86 } 87 88 89 /** 90 * Callback to process POST /dkg-commitment response 91 * 92 * @param cls the `struct FROSIX_DkgCommitmentRequestOperation` 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_commitment_request_finished (void *cls, 99 long response_code, 100 const void *response) 101 { 102 struct FROSIX_DkgCommitmentRequestOperation *dco = cls; 103 struct FROSIX_DkgCommitmentRequestDetails dcd; 104 const json_t *json_response = response; 105 106 dco->job = NULL; 107 dcd.http_status = response_code; 108 dcd.ec = TALER_EC_NONE; 109 110 switch (response_code) 111 { 112 case 0: 113 /* Hard error */ 114 GNUNET_break (0); 115 dcd.dcs = FROSIX_DCS_HTTP_ERROR; 116 dcd.ec = TALER_EC_GENERIC_INVALID_RESPONSE; 117 break; 118 case MHD_HTTP_CREATED: 119 { 120 dcd.dcs = FROSIX_DCS_SUCCESS; 121 dcd.provider_index = dco->provider_index; 122 123 /* temp commitment struct */ 124 struct FROST_DkgCommitment commitment; 125 126 /* We got a result, lets parse it */ 127 json_t *dkg_commitment = NULL; 128 struct GNUNET_JSON_Specification spec[] = { 129 GNUNET_JSON_spec_uint8 ("provider_index", 130 &dcd.dkg_commitment.identifier), 131 GNUNET_JSON_spec_json ("dkg_commitment", 132 &dkg_commitment), 133 GNUNET_JSON_spec_fixed_auto ("zkp_r", 134 &commitment.zkp.r), 135 GNUNET_JSON_spec_fixed_auto ("zkp_z", 136 &commitment.zkp.z), 137 GNUNET_JSON_spec_fixed_auto ("public_key", 138 &dcd.public_key), 139 GNUNET_JSON_spec_end () 140 }; 141 142 if (GNUNET_OK != 143 GNUNET_JSON_parse (json_response, 144 spec, 145 NULL, 146 NULL)) 147 { 148 /* Parsing failed! */ 149 GNUNET_break_op (0); 150 dcd.http_status = 0; 151 GNUNET_JSON_parse_free (spec); 152 break; 153 } 154 155 /* check if number of commitment values is in allowed range */ 156 if (0 >= json_array_size (dkg_commitment) 157 || json_array_size (dkg_commitment) >= 254) 158 { 159 GNUNET_break_op (0); 160 dcd.http_status = 0; 161 GNUNET_JSON_parse_free (spec); 162 break; 163 } 164 165 dcd.dkg_commitment.shares_commitments_length = \ 166 (uint8_t) json_array_size (dkg_commitment); 167 168 /* initialize struct dkg_commitment */ 169 FROST_initialize_dkg_commitment ( 170 &dcd.dkg_commitment, 171 dcd.dkg_commitment.identifier, 172 dcd.dkg_commitment.shares_commitments_length); 173 174 /* copy back from temp commitment struct */ 175 memcpy (&dcd.dkg_commitment.zkp.r, 176 &commitment.zkp.r, 177 sizeof (commitment.zkp.r)); 178 memcpy (&dcd.dkg_commitment.zkp.z, 179 &commitment.zkp.z, 180 sizeof (commitment.zkp.z)); 181 182 /* parse commitment values */ 183 for (unsigned int i = 0; i < dcd.dkg_commitment.shares_commitments_length; 184 i++) 185 { 186 struct GNUNET_JSON_Specification comm_spec[] = { 187 GNUNET_JSON_spec_fixed_auto (NULL, 188 &dcd.dkg_commitment.share_comm[i]), 189 GNUNET_JSON_spec_end () 190 }; 191 192 if (GNUNET_OK != 193 GNUNET_JSON_parse (json_array_get (dkg_commitment, 194 i), 195 comm_spec, 196 NULL, 197 NULL)) 198 { 199 GNUNET_break_op (0); 200 GNUNET_JSON_parse_free (comm_spec); 201 GNUNET_JSON_parse_free (spec); 202 FROST_free_dkg_commitment (&dcd.dkg_commitment, 203 1); 204 dcd.http_status = 0; 205 break; 206 } 207 208 GNUNET_JSON_parse_free (comm_spec); 209 } 210 211 GNUNET_JSON_parse_free (spec); 212 break; 213 } 214 case MHD_HTTP_BAD_REQUEST: 215 /* We have a conflict with the API */ 216 GNUNET_break (0); 217 dcd.dcs = FROSIX_DCS_CLIENT_ERROR; 218 dcd.ec = TALER_JSON_get_error_code2 (json_response, 219 json_object_size (json_response)); 220 break; 221 case MHD_HTTP_INTERNAL_SERVER_ERROR: 222 /* The provider has a problem! */ 223 GNUNET_break (0); 224 dcd.dcs = FROSIX_DCS_SERVER_ERROR; 225 dcd.ec = TALER_JSON_get_error_code2 (json_response, 226 json_object_size (json_response)); 227 break; 228 default: 229 /* Unexpected response code */ 230 GNUNET_break (0); 231 dcd.ec = TALER_JSON_get_error_code2 (json_response, 232 json_object_size (json_response)); 233 break; 234 } 235 236 /* return to callback function with the data from the response */ 237 dco->cb (dco->cb_cls, 238 &dcd); 239 dco->cb = NULL; 240 241 FROST_free_dkg_commitment (&dcd.dkg_commitment, 242 1); 243 244 FROSIX_dkg_commitment_request_cancel (dco); 245 } 246 247 248 /** 249 * Handle HTTP header received by curl. 250 * 251 * @param buffer one line of HTTP header data 252 * @param size size of an item 253 * @param userdata our `struct FROSIX_DkgCommitmentRequestOperation` 254 * @return `size * nitems` 255 */ 256 static size_t 257 handle_header (char *buffer, 258 size_t size, 259 size_t nitems, 260 void *userdata) 261 { 262 size_t total = size * nitems; 263 return total; 264 } 265 266 267 struct FROSIX_DkgCommitmentRequestOperation * 268 FROSIX_dkg_commitment_request ( 269 struct GNUNET_CURL_Context *ctx, 270 const char *backend_url, 271 const struct FROSIX_DkgRequestIdP *uuid, 272 uint8_t identifier, 273 uint8_t threshold, 274 uint8_t num_of_participants, 275 const struct FROSIX_DkgContextStringP *context_string, 276 const struct FROSIX_ChallengeHashP *challenge_hash, 277 const struct GNUNET_CRYPTO_EddsaPublicKey providers_public_keys[], 278 FROSIX_DkgCommitmentRequestCallback cb, 279 void *cb_cls) 280 { 281 struct FROSIX_DkgCommitmentRequestOperation *dco; 282 CURL *eh; 283 char *json_str; 284 285 /* check if we got a callback function, abort if not */ 286 GNUNET_assert (NULL != cb); 287 288 dco = GNUNET_new (struct FROSIX_DkgCommitmentRequestOperation); 289 290 { 291 /* prepare URL */ 292 char *uuid_str; 293 char *path; 294 295 uuid_str = GNUNET_STRINGS_data_to_string_alloc (uuid, 296 sizeof (*uuid)); 297 298 GNUNET_asprintf (&path, 299 "dkg-commitment/%s", 300 uuid_str); 301 302 dco->url = TALER_url_join (backend_url, 303 path, 304 NULL); 305 306 GNUNET_free (path); 307 GNUNET_free (uuid_str); 308 } 309 310 dco->provider_index = identifier; 311 312 /* array for all providers public keys */ 313 json_t *json_public_keys = json_array (); 314 315 316 for (unsigned int i = 0; i < num_of_participants; i++) 317 { 318 /* single public key */ 319 json_t *public_key; 320 public_key = GNUNET_JSON_PACK ( 321 GNUNET_JSON_pack_data_auto (NULL, 322 &providers_public_keys[i])); 323 324 /* add to public key array */ 325 GNUNET_assert (0 == 326 json_array_append_new ( 327 json_public_keys, 328 public_key)); 329 } 330 331 { 332 /* pack the json object for the request body */ 333 json_t *dkg_commitment_data; 334 dkg_commitment_data = GNUNET_JSON_PACK ( 335 GNUNET_JSON_pack_uint64 ("provider_index", 336 identifier), 337 GNUNET_JSON_pack_uint64 ("threshold", 338 threshold), 339 GNUNET_JSON_pack_data_auto ("context_string", 340 context_string), 341 GNUNET_JSON_pack_data_auto ("auth_hash", 342 challenge_hash), 343 GNUNET_JSON_pack_array_steal ("providers_public_keys", 344 json_public_keys)); 345 json_str = json_dumps (dkg_commitment_data, 346 JSON_COMPACT); 347 348 json_decref (dkg_commitment_data); 349 350 /* check if we have a json object, abort if it was not successful */ 351 GNUNET_assert (NULL != json_str); 352 } 353 354 /* prepare curl options and fire the request */ 355 dco->ctx = ctx; 356 dco->cb = cb; 357 dco->cb_cls = cb_cls; 358 359 eh = FROSIX_curl_easy_get_ (dco->url); 360 361 GNUNET_assert (CURLE_OK == 362 curl_easy_setopt (eh, 363 CURLOPT_POSTFIELDS, 364 json_str)); 365 GNUNET_assert (CURLE_OK == 366 curl_easy_setopt (eh, 367 CURLOPT_POSTFIELDSIZE, 368 strlen (json_str))); 369 GNUNET_assert (CURLE_OK == 370 curl_easy_setopt (eh, 371 CURLOPT_HEADERFUNCTION, 372 &handle_header)); 373 GNUNET_assert (CURLE_OK == 374 curl_easy_setopt (eh, 375 CURLOPT_HEADERDATA, 376 dco)); 377 378 dco->job = GNUNET_CURL_job_add (ctx, 379 eh, 380 &handle_dkg_commitment_request_finished, 381 dco); 382 383 return dco; 384 }