frosix-httpd_dkg-commitment.c (11688B)
1 /* 2 This file is part of Frosix 3 Copyright (C) 2022, 2023 Joel Urech 4 5 Frosix is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Affero General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 Frosix is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. 12 13 You should have received a copy of the GNU Affero General Public License along with 14 Frosix; see the file COPYING. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file backend/frosix-httpd_commitment.c 18 * @brief functions to handle incoming requests on /dkg-commitment 19 * @author Joel Urech 20 */ 21 #include "frosix-httpd_dkg.h" 22 #include "frosix-httpd.h" 23 #include "frosix_service.h" 24 #include "keygen.h" 25 #include <taler/taler_util.h> 26 #include <gnunet/gnunet_util_lib.h> 27 28 #define HASHCONTEXT "FROSIX-DKG" 29 30 /** 31 * Context for an dkg commitment operation 32 */ 33 struct DkgCommitmentContext 34 { 35 /** 36 * Our unique identifier value in the dkg process. 37 */ 38 uint8_t provider_index; 39 40 /** 41 * Number of providers which has to collaborate in order to generate a valid signature. 42 */ 43 uint8_t threshold; 44 45 /** 46 * Total number of providers participating in the distributed key generation process. 47 */ 48 uint8_t num_of_participants; 49 50 /** 51 * High entropy string, which should be only used for one distributed key generation process. 52 * The resulting commitment will be deterministically derived from this context string. 53 */ 54 struct FROSIX_DkgContextStringP context_string; 55 56 /** 57 * Salted hash of the chosen challenge method. 58 */ 59 struct FROSIX_ChallengeHashP auth_hash; 60 61 /** 62 * Id of the request, hash of all submitted values. 63 */ 64 struct FROSIX_DkgRequestIdP request_id; 65 66 /** 67 * 68 */ 69 struct FROSIX_ProviderSaltP provider_salt; 70 71 /** 72 * 73 */ 74 struct FROSIX_SecretProviderSaltP secret_provider_salt; 75 76 /** 77 * 78 */ 79 struct GNUNET_CRYPTO_EddsaPublicKey pub_sig_key; 80 81 /** 82 * 83 */ 84 struct GNUNET_CRYPTO_EddsaPrivateKey priv_sig_key; 85 86 /** 87 * Our handler context 88 */ 89 struct TM_HandlerContext *hc; 90 91 /** 92 * Uploaded JSON data, NULL if upload is not yet complete. 93 */ 94 json_t *json; 95 96 /** 97 * Post parser context. 98 */ 99 void *post_ctx; 100 101 /** 102 * Connection handle for closing or resuming 103 */ 104 struct MHD_Connection *connection; 105 106 /** 107 * When should this request time out? 108 */ 109 struct GNUNET_TIME_Absolute timeout; 110 111 }; 112 113 114 /** 115 * Return the generated dkg_commitment 116 * 117 * @param connection 118 * @param dkg_comm 119 * @return 120 */ 121 static MHD_RESULT 122 return_dkg_commitment ( 123 struct MHD_Connection *connection, 124 const struct GNUNET_CRYPTO_EddsaPublicKey *pub_sig_key, 125 const struct FROST_DkgCommitment *dkg_comm) 126 { 127 // Prepare commit 128 json_t *commits; 129 commits = json_array (); 130 GNUNET_assert (NULL != commits); 131 132 for (int i = 0; i < dkg_comm->shares_commitments_length; i++) 133 { 134 GNUNET_assert (0 == 135 json_array_append ( 136 commits, 137 GNUNET_JSON_from_data_auto (&dkg_comm->share_comm[i]))); 138 } 139 140 // Return everything 141 return TALER_MHD_REPLY_JSON_PACK ( 142 connection, 143 MHD_HTTP_CREATED, 144 GNUNET_JSON_pack_uint64 ("provider_index", 145 dkg_comm->identifier), 146 GNUNET_JSON_pack_array_steal ("dkg_commitment", 147 commits), 148 GNUNET_JSON_pack_data_auto ("zkp_r", 149 &dkg_comm->zkp.r), 150 GNUNET_JSON_pack_data_auto ("zkp_z", 151 &dkg_comm->zkp.z), 152 GNUNET_JSON_pack_data_auto ("public_key", 153 pub_sig_key)); 154 } 155 156 MHD_RESULT 157 FH_handler_dkg_commitment_post ( 158 struct MHD_Connection *connection, 159 struct TM_HandlerContext *hc, 160 const struct FROSIX_DkgRequestIdP *dkg_id, 161 const struct FROSIX_ProviderSaltP *provider_salt, 162 const struct FROSIX_SecretProviderSaltP *secret_provider_salt, 163 const struct GNUNET_CRYPTO_EddsaPrivateKey *priv_sig_key, 164 const struct GNUNET_CRYPTO_EddsaPublicKey *pub_sig_key, 165 const char *dkg_commitment_data, 166 size_t *dkg_commitment_data_size) 167 { 168 enum GNUNET_GenericReturnValue res; 169 struct DkgCommitmentContext *dc = hc->ctx; 170 json_t *json_ppk = NULL; 171 172 if (NULL == dc) 173 { 174 dc = GNUNET_new (struct DkgCommitmentContext); 175 dc->connection = connection; 176 dc->request_id = *dkg_id; 177 dc->provider_salt = *provider_salt; 178 dc->secret_provider_salt = *secret_provider_salt; 179 dc->priv_sig_key = *priv_sig_key; 180 dc->pub_sig_key = *pub_sig_key; 181 hc->ctx = dc; 182 } 183 184 /* parse request body */ 185 if (NULL == dc->json) 186 { 187 res = TALER_MHD_parse_post_json (connection, 188 &dc->post_ctx, 189 dkg_commitment_data, 190 dkg_commitment_data_size, 191 &dc->json); 192 if (GNUNET_SYSERR == res) 193 { 194 GNUNET_break (0); 195 return MHD_NO; 196 } 197 if ((GNUNET_NO == res || 198 (NULL == dc->json))) 199 { 200 return MHD_YES; 201 } 202 } 203 204 struct GNUNET_JSON_Specification spec[] = { 205 GNUNET_JSON_spec_uint8 ("provider_index", 206 &dc->provider_index), 207 GNUNET_JSON_spec_uint8 ("threshold", 208 &dc->threshold), 209 GNUNET_JSON_spec_fixed_auto ("context_string", 210 &dc->context_string), 211 GNUNET_JSON_spec_fixed_auto ("auth_hash", 212 &dc->auth_hash), 213 GNUNET_JSON_spec_json ("providers_public_keys", 214 &json_ppk), 215 GNUNET_JSON_spec_end () 216 }; 217 218 res = TALER_MHD_parse_json_data (connection, 219 dc->json, 220 spec); 221 if (GNUNET_SYSERR == res) 222 { 223 GNUNET_break_op (0); 224 return TALER_MHD_reply_with_error (connection, 225 MHD_HTTP_INTERNAL_SERVER_ERROR, 226 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 227 "Unable to parse request body"); 228 } 229 if (GNUNET_NO == res) 230 { 231 GNUNET_break_op (0); 232 return TALER_MHD_reply_with_error (connection, 233 MHD_HTTP_BAD_REQUEST, 234 TALER_EC_GENERIC_PARAMETER_MALFORMED, 235 "Unable to parse request body"); 236 } 237 238 /* check number of submitted provider public keys*/ 239 if (254 < json_array_size (json_ppk)) 240 { 241 GNUNET_JSON_parse_free (spec); 242 GNUNET_break_op (0); 243 return TALER_MHD_reply_with_error (connection, 244 MHD_HTTP_BAD_REQUEST, 245 TALER_EC_GENERIC_PARAMETER_MALFORMED, 246 "Too many provider public keys"); 247 } 248 249 /* set number of participants */ 250 dc->num_of_participants = json_array_size (json_ppk); 251 252 /* validate provider index, threshold and num_of_participants */ 253 if (GNUNET_OK != FROST_validate_dkg_params (dc->provider_index, 254 dc->threshold, 255 dc->num_of_participants)) 256 { 257 GNUNET_JSON_parse_free (spec); 258 GNUNET_break_op (0); 259 return TALER_MHD_reply_with_error (connection, 260 MHD_HTTP_BAD_REQUEST, 261 TALER_EC_GENERIC_PARAMETER_MALFORMED, 262 "Parameters out ouf bound"); 263 } 264 265 /* Check if called id is matching the send data */ 266 if (GNUNET_OK != FROSIX_dkg_validate_request_id_ ( 267 &dc->request_id, 268 &dc->context_string, 269 &dc->auth_hash, 270 &dc->provider_salt, 271 dc->provider_index, 272 dc->num_of_participants, 273 dc->threshold)) 274 { 275 GNUNET_JSON_parse_free (spec); 276 GNUNET_break_op (0); 277 return TALER_MHD_reply_with_error (connection, 278 MHD_HTTP_BAD_REQUEST, 279 TALER_EC_GENERIC_PARAMETER_MALFORMED, 280 "ID in URL not matching data in body"); 281 } 282 283 /* parse providers public keys */ 284 struct GNUNET_CRYPTO_EddsaPublicKey 285 providers_public_keys[dc->num_of_participants]; 286 for (unsigned int i = 0; i < dc->num_of_participants; i++) 287 { 288 struct GNUNET_JSON_Specification ppk_spec[] = { 289 GNUNET_JSON_spec_fixed_auto (NULL, 290 &providers_public_keys[i]), 291 GNUNET_JSON_spec_end () 292 }; 293 294 res = TALER_MHD_parse_json_array (connection, 295 json_ppk, 296 ppk_spec, 297 i, 298 -1); 299 300 if (GNUNET_SYSERR == res) 301 { 302 GNUNET_JSON_parse_free (spec); 303 GNUNET_JSON_parse_free (ppk_spec); 304 GNUNET_break (0); 305 return MHD_NO; 306 } 307 if (GNUNET_NO == res) 308 { 309 GNUNET_JSON_parse_free (spec); 310 GNUNET_JSON_parse_free (ppk_spec); 311 GNUNET_break_op (0); 312 return TALER_MHD_reply_with_error (connection, 313 MHD_HTTP_BAD_REQUEST, 314 TALER_EC_GENERIC_PARAMETER_MALFORMED, 315 "Unable to parse request body"); 316 } 317 318 GNUNET_JSON_parse_free (ppk_spec); 319 } 320 321 GNUNET_JSON_parse_free (spec); 322 323 /* FIXME: check if any of the submitted public key is ours */ 324 325 /* derive the final context string */ 326 struct FROST_DkgContextString cs_h; 327 if (GNUNET_YES != FROSIX_dkg_derive_context_string_ ( 328 &cs_h, 329 dc->provider_index, 330 dc->threshold, 331 &dc->context_string, 332 &dc->auth_hash, 333 providers_public_keys, 334 dc->num_of_participants, 335 &dc->secret_provider_salt)) 336 { 337 GNUNET_break (0); 338 return TALER_MHD_reply_with_error (connection, 339 MHD_HTTP_INTERNAL_SERVER_ERROR, 340 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 341 "Derive context string"); 342 } 343 344 /* hash public key */ 345 struct FROST_HashState h_s; 346 struct FROST_HashCode pub_key_hash; 347 FROST_hash_init (&h_s); 348 FROST_hash_fixed_update (&h_s, 349 &dc->pub_sig_key, 350 sizeof (dc->pub_sig_key)); 351 FROST_hash_final (&h_s, 352 &pub_key_hash); 353 354 /* create shares with zkp including hashed pk */ 355 struct FROST_DkgCommitment dkg_commitment; 356 357 if (GNUNET_OK != FROSIX_dkg_commitment_generate_ (&dkg_commitment, 358 &cs_h, 359 &pub_key_hash, 360 dc->provider_index, 361 dc->threshold, 362 dc->num_of_participants)) 363 { 364 GNUNET_break (0); 365 return TALER_MHD_reply_with_error (connection, 366 MHD_HTTP_INTERNAL_SERVER_ERROR, 367 TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE, 368 "Generate DKG commitment"); 369 } 370 371 res = return_dkg_commitment (connection, 372 &dc->pub_sig_key, 373 &dkg_commitment); 374 375 FROST_free_dkg_commitment (&dkg_commitment, 376 1); 377 378 return res; 379 }