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 }