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 }