diff options
author | Christian Grothoff <christian@grothoff.org> | 2015-01-29 15:45:05 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2015-01-29 15:45:05 +0100 |
commit | 4a27969e5e439fb0f277dcf9f0461817d83e36b4 (patch) | |
tree | 9dbcea3e7bb5723438a1817a9a8c840f55ce92f2 | |
parent | a284561298af60ade27eb18008f29ebf63ac62b7 (diff) |
make TALER_MINT_parse_json_data more expressive, add RSA types as well
-rw-r--r-- | src/mint/taler-mint-httpd_deposit.c | 29 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_parsing.c | 643 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_parsing.h | 37 | ||||
-rw-r--r-- | src/mint/taler-mint-httpd_refresh.c | 183 |
4 files changed, 528 insertions, 364 deletions
diff --git a/src/mint/taler-mint-httpd_deposit.c b/src/mint/taler-mint-httpd_deposit.c index ec75c3ec0..78d424b80 100644 --- a/src/mint/taler-mint-httpd_deposit.c +++ b/src/mint/taler-mint-httpd_deposit.c @@ -127,8 +127,8 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection, char *wire_enc; size_t len; struct GNUNET_MINT_ParseFieldSpec spec[] = { - TALER_MINT_PARSE_VARIABLE ("denom_pub"), - TALER_MINT_PARSE_VARIABLE ("ubsig"), + TALER_MINT_PARSE_RSA_PUBLIC_KEY ("denom_pub", &deposit.coin.denom_pub), + TALER_MINT_PARSE_RSA_SIGNATURE ("ubsig", &deposit.coin.denom_sig), TALER_MINT_PARSE_FIXED ("coin_pub", &deposit.coin.coin_pub), TALER_MINT_PARSE_FIXED ("merchant_pub", &deposit.merchant_pub), TALER_MINT_PARSE_FIXED ("H_a", &deposit.h_contract), @@ -146,32 +146,9 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection, return MHD_NO; /* hard failure */ if (GNUNET_NO == res) return MHD_YES; /* failure */ - deposit.coin.denom_pub - = GNUNET_CRYPTO_rsa_public_key_decode (spec[0].destination, - spec[0].destination_size_out); - if (NULL == deposit.coin.denom_pub) - { - LOG_WARNING ("Failed to parse denomination key for /deposit request\n"); - TALER_MINT_release_parsed_data (spec); - return TALER_MINT_reply_arg_invalid (connection, - "denom_pub"); - } - deposit.coin.denom_sig - = GNUNET_CRYPTO_rsa_signature_decode (spec[1].destination, - spec[1].destination_size_out); - if (NULL == deposit.coin.denom_sig) - { - LOG_WARNING ("Failed to parse unblinded signature for /deposit request\n"); - GNUNET_CRYPTO_rsa_public_key_free (deposit.coin.denom_pub); - TALER_MINT_release_parsed_data (spec); - return TALER_MINT_reply_arg_invalid (connection, - "denom_pub"); - } /* FIXME: check that "wire" is formatted correctly */ if (NULL == (wire_enc = json_dumps (wire, JSON_COMPACT | JSON_SORT_KEYS))) { - GNUNET_CRYPTO_rsa_public_key_free (deposit.coin.denom_pub); - GNUNET_CRYPTO_rsa_signature_free (deposit.coin.denom_sig); LOG_WARNING ("Failed to parse JSON wire format specification for /deposit request\n"); TALER_MINT_release_parsed_data (spec); return TALER_MINT_reply_arg_invalid (connection, @@ -187,8 +164,6 @@ parse_and_handle_deposit_request (struct MHD_Connection *connection, deposit.amount = *amount; res = verify_and_execute_deposit (connection, &deposit); - GNUNET_CRYPTO_rsa_public_key_free (deposit.coin.denom_pub); - GNUNET_CRYPTO_rsa_signature_free (deposit.coin.denom_sig); TALER_MINT_release_parsed_data (spec); return res; } diff --git a/src/mint/taler-mint-httpd_parsing.c b/src/mint/taler-mint-httpd_parsing.c index 165654193..9c732ce6e 100644 --- a/src/mint/taler-mint-httpd_parsing.c +++ b/src/mint/taler-mint-httpd_parsing.c @@ -261,6 +261,106 @@ TALER_MINT_parse_post_cleanup_callback (void *con_cls) /** + * Extract base32crockford encoded data from request. + * + * Queues an error response to the connection if the parameter is missing or + * invalid. + * + * @param connection the MHD connection + * @param param_name the name of the parameter with the key + * @param[out] out_data pointer to store the result + * @param out_size expected size of data + * @return + * #GNUNET_YES if the the argument is present + * #GNUNET_NO if the argument is absent or malformed + * #GNUNET_SYSERR on internal error (error response could not be sent) + */ +int +TALER_MINT_mhd_request_arg_data (struct MHD_Connection *connection, + const char *param_name, + void *out_data, + size_t out_size) +{ + const char *str; + + str = MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, + param_name); + if (NULL == str) + { + return (MHD_NO == + TALER_MINT_reply_arg_missing (connection, param_name)) + ? GNUNET_SYSERR : GNUNET_NO; + } + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (str, + strlen (str), + out_data, + out_size)) + return (MHD_NO == + TALER_MINT_reply_arg_invalid (connection, param_name)) + ? GNUNET_SYSERR : GNUNET_NO; + return GNUNET_OK; +} + + +/** + * Extraxt variable-size base32crockford encoded data from request. + * + * Queues an error response to the connection if the parameter is missing + * or the encoding is invalid. + * + * @param connection the MHD connection + * @param param_name the name of the parameter with the key + * @param[out] out_data pointer to allocate buffer and store the result + * @param[out] out_size set to the size of the buffer allocated in @a out_data + * @return + * #GNUNET_YES if the the argument is present + * #GNUNET_NO if the argument is absent or malformed + * #GNUNET_SYSERR on internal error (error response could not be sent) + */ +int +TALER_MINT_mhd_request_var_arg_data (struct MHD_Connection *connection, + const char *param_name, + void **out_data, + size_t *out_size) +{ + const char *str; + size_t slen; + size_t olen; + void *out; + + str = MHD_lookup_connection_value (connection, + MHD_GET_ARGUMENT_KIND, + param_name); + if (NULL == str) + { + return (MHD_NO == + TALER_MINT_reply_arg_missing (connection, param_name)) + ? GNUNET_SYSERR : GNUNET_NO; + } + slen = strlen (str); + olen = (slen * 5) / 8; + out = GNUNET_malloc (olen); + if (GNUNET_OK != + GNUNET_STRINGS_string_to_data (str, + strlen (str), + out, + olen)) + { + GNUNET_free (out); + *out_size = 0; + return (MHD_NO == + TALER_MINT_reply_arg_invalid (connection, param_name)) + ? GNUNET_SYSERR : GNUNET_NO; + } + *out_data = out; + *out_size = olen; + return GNUNET_OK; +} + + +/** * Navigate through a JSON tree. * * Sends an error response if navigation is impossible (i.e. @@ -295,165 +395,298 @@ GNUNET_MINT_parse_navigate_json (struct MHD_Connection *connection, switch (command) { - case JNAV_FIELD: + case JNAV_FIELD: + { + const char *fname = va_arg(argp, const char *); + + json_array_append_new (path, + json_string (fname)); + root = json_object_get (root, + fname); + if (NULL == root) { - const char *fname = va_arg(argp, const char *); + ret = (MHD_YES == + TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:s, s:o}", + "error", + "missing field in JSON", + "field", + fname, + "path", + path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + } + break; - json_array_append_new (path, - json_string (fname)); - root = json_object_get (root, - fname); - if (NULL == root) - { - ret = (MHD_YES == - TALER_MINT_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:s, s:o}", - "error", - "missing field in JSON", - "field", - fname, - "path", - path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } + case JNAV_INDEX: + { + int fnum = va_arg(argp, int); + + json_array_append_new (path, + json_integer (fnum)); + root = json_array_get (root, + fnum); + if (NULL == root) + { + ret = (MHD_YES == + TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:o}", + "error", + "missing index in JSON", + "path", path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; } - break; - case JNAV_INDEX: + } + break; + + case JNAV_RET_DATA: + { + void *where = va_arg (argp, void *); + size_t len = va_arg (argp, size_t); + const char *str; + int res; + + // FIXME: avoidable code duplication here... + str = json_string_value (root); + if (NULL == str) + { + ret = (MHD_YES == + TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:o}", + "error", + "string expected", + "path", + path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + res = GNUNET_STRINGS_string_to_data (str, strlen (str), + where, len); + if (GNUNET_OK != res) { - int fnum = va_arg(argp, int); + ret = (MHD_YES == + TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:o}", + "error", + "malformed binary data in JSON", + "path", + path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + ret = GNUNET_OK; + } + break; - json_array_append_new (path, - json_integer (fnum)); - root = json_array_get (root, - fnum); - if (NULL == root) - { - ret = (MHD_YES == - TALER_MINT_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:o}", - "error", - "missing index in JSON", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } + case JNAV_RET_DATA_VAR: + { + void **where = va_arg (argp, void **); + size_t *len = va_arg (argp, size_t *); + const char *str; + + // FIXME: avoidable code duplication here... + str = json_string_value (root); + if (NULL == str) + { + ret = (MHD_YES == + TALER_MINT_reply_internal_error (connection, + "json_string_value() failed")) + ? GNUNET_NO : GNUNET_SYSERR; + break; } - break; - case JNAV_RET_DATA: + *len = (strlen (str) * 5) / 8; + if (NULL != where) { - void *where = va_arg (argp, void *); - size_t len = va_arg (argp, size_t); - const char *str; int res; - str = json_string_value (root); - if (NULL == str) - { - ret = (MHD_YES == - TALER_MINT_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:o}", - "error", - "string expected", - "path", - path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - res = GNUNET_STRINGS_string_to_data (str, strlen (str), - where, len); + *where = GNUNET_malloc (*len); + res = GNUNET_STRINGS_string_to_data (str, + strlen (str), + *where, + *len); if (GNUNET_OK != res) { + GNUNET_free (*where); + *where = NULL; + *len = 0; ret = (MHD_YES == TALER_MINT_reply_json_pack (connection, MHD_HTTP_BAD_REQUEST, "{s:s, s:o}", "error", "malformed binary data in JSON", - "path", - path)) + "path", path)) ? GNUNET_NO : GNUNET_SYSERR; break; } - ret = GNUNET_OK; } - break; - case JNAV_RET_DATA_VAR: + ret = GNUNET_OK; + } + break; + + case JNAV_RET_TYPED_JSON: + { + int typ = va_arg (argp, int); + const json_t **r_json = va_arg (argp, const json_t **); + + if ( (-1 != typ) && (json_typeof (root) != typ)) { - void **where = va_arg (argp, void **); - size_t *len = va_arg (argp, size_t *); - const char *str; + ret = (MHD_YES == + TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:i, s:i, s:o}", + "error", "wrong JSON field type", + "type_expected", typ, + "type_actual", json_typeof (root), + "path", path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + *r_json = root; + ret = GNUNET_OK; + } + break; - str = json_string_value (root); - if (NULL == str) - { - ret = (MHD_YES == - TALER_MINT_reply_internal_error (connection, - "json_string_value() failed")) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - *len = (strlen (str) * 5) / 8; - if (NULL != where) - { - int res; - - *where = GNUNET_malloc (*len); - res = GNUNET_STRINGS_string_to_data (str, - strlen (str), - *where, - *len); - if (GNUNET_OK != res) - { - GNUNET_free (*where); - *where = NULL; - *len = 0; - ret = (MHD_YES == - TALER_MINT_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:o}", - "error", - "malformed binary data in JSON", - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - } - ret = GNUNET_OK; + case JNAV_RET_RSA_PUBLIC_KEY: + { + void **where = va_arg (argp, void **); + size_t len; + const char *str; + int res; + void *buf; + + // FIXME: avoidable code duplication here... + str = json_string_value (root); + if (NULL == str) + { + ret = (MHD_YES == + TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:o}", + "error", + "string expected", + "path", + path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; } - break; - case JNAV_RET_TYPED_JSON: + len = (strlen (str) * 5) / 8; + buf = GNUNET_malloc (len); + res = GNUNET_STRINGS_string_to_data (str, + strlen (str), + buf, + len); + if (GNUNET_OK != res) { - int typ = va_arg (argp, int); - const json_t **r_json = va_arg (argp, const json_t **); - - if ( (-1 != typ) && (json_typeof (root) != typ)) - { - ret = (MHD_YES == - TALER_MINT_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s, s:i, s:i, s:o}", - "error", "wrong JSON field type", - "type_expected", typ, - "type_actual", json_typeof (root), - "path", path)) - ? GNUNET_NO : GNUNET_SYSERR; - break; - } - *r_json = root; - ret = GNUNET_OK; + GNUNET_free (buf); + ret = (MHD_YES == + TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:o}", + "error", + "malformed binary data in JSON", + "path", + path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; } + *where = GNUNET_CRYPTO_rsa_public_key_decode (buf, + len); + GNUNET_free (buf); + if (NULL == *where) + { + ret = (MHD_YES == + TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:o}", + "error", + "malformed RSA public key in JSON", + "path", + path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + ret = GNUNET_OK; break; - default: - GNUNET_break (0); - ret = (MHD_YES == - TALER_MINT_reply_internal_error (connection, - "unhandled value in switch")) - ? GNUNET_NO : GNUNET_SYSERR; + } + + case JNAV_RET_RSA_SIGNATURE: + { + void **where = va_arg (argp, void **); + size_t len; + const char *str; + int res; + void *buf; + + // FIXME: avoidable code duplication here... + str = json_string_value (root); + if (NULL == str) + { + ret = (MHD_YES == + TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:o}", + "error", + "string expected", + "path", + path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + len = (strlen (str) * 5) / 8; + buf = GNUNET_malloc (len); + res = GNUNET_STRINGS_string_to_data (str, + strlen (str), + buf, + len); + if (GNUNET_OK != res) + { + GNUNET_free (buf); + ret = (MHD_YES == + TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:o}", + "error", + "malformed binary data in JSON", + "path", + path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + *where = GNUNET_CRYPTO_rsa_signature_decode (buf, + len); + GNUNET_free (buf); + if (NULL == *where) + { + ret = (MHD_YES == + TALER_MINT_reply_json_pack (connection, + MHD_HTTP_BAD_REQUEST, + "{s:s, s:o}", + "error", + "malformed RSA signature in JSON", + "path", + path)) + ? GNUNET_NO : GNUNET_SYSERR; + break; + } + ret = GNUNET_OK; break; + } + + default: + GNUNET_break (0); + ret = (MHD_YES == + TALER_MINT_reply_internal_error (connection, + "unhandled value in switch")) + ? GNUNET_NO : GNUNET_SYSERR; + break; } } va_end (argp); @@ -531,6 +764,30 @@ TALER_MINT_parse_json_data (struct MHD_Connection *connection, JNAV_RET_TYPED_JSON, spec[i].type, &ptr); + *((void**)spec[i].destination) = ptr; + break; + case JNAV_RET_RSA_PUBLIC_KEY: + if (GNUNET_YES != ret) + break; + ptr = NULL; + ret = GNUNET_MINT_parse_navigate_json (connection, + root, + JNAV_FIELD, + spec[i].field_name, + JNAV_RET_RSA_PUBLIC_KEY, + &ptr); + spec[i].destination = ptr; + break; + case JNAV_RET_RSA_SIGNATURE: + if (GNUNET_YES != ret) + break; + ptr = NULL; + ret = GNUNET_MINT_parse_navigate_json (connection, + root, + JNAV_FIELD, + spec[i].field_name, + JNAV_RET_RSA_SIGNATURE, + &ptr); spec[i].destination = ptr; break; } @@ -551,6 +808,7 @@ void TALER_MINT_release_parsed_data (struct GNUNET_MINT_ParseFieldSpec *spec) { unsigned int i; + void *ptr; for (i=0; NULL != spec[i].field_name; i++) { @@ -573,10 +831,27 @@ TALER_MINT_release_parsed_data (struct GNUNET_MINT_ParseFieldSpec *spec) } break; case JNAV_RET_TYPED_JSON: - if (NULL != spec[i].destination) + ptr = *(void **) spec[i].destination; + if (NULL != ptr) { - json_decref (spec[i].destination); - spec[i].destination = NULL; + json_decref (ptr); + *(void**) spec[i].destination = NULL; + } + break; + case JNAV_RET_RSA_PUBLIC_KEY: + ptr = *(void **) spec[i].destination; + if (NULL != ptr) + { + GNUNET_CRYPTO_rsa_public_key_free (ptr); + *(void**) spec[i].destination = NULL; + } + break; + case JNAV_RET_RSA_SIGNATURE: + ptr = *(void **) spec[i].destination; + if (NULL != ptr) + { + GNUNET_CRYPTO_rsa_signature_free (ptr); + *(void**) spec[i].destination = NULL; } break; } @@ -656,105 +931,5 @@ TALER_MINT_parse_amount_json (struct MHD_Connection *connection, } -/** - * Extract base32crockford encoded data from request. - * - * Queues an error response to the connection if the parameter is missing or - * invalid. - * - * @param connection the MHD connection - * @param param_name the name of the parameter with the key - * @param[out] out_data pointer to store the result - * @param out_size expected size of data - * @return - * #GNUNET_YES if the the argument is present - * #GNUNET_NO if the argument is absent or malformed - * #GNUNET_SYSERR on internal error (error response could not be sent) - */ -int -TALER_MINT_mhd_request_arg_data (struct MHD_Connection *connection, - const char *param_name, - void *out_data, - size_t out_size) -{ - const char *str; - - str = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - param_name); - if (NULL == str) - { - return (MHD_NO == - TALER_MINT_reply_arg_missing (connection, param_name)) - ? GNUNET_SYSERR : GNUNET_NO; - } - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (str, - strlen (str), - out_data, - out_size)) - return (MHD_NO == - TALER_MINT_reply_arg_invalid (connection, param_name)) - ? GNUNET_SYSERR : GNUNET_NO; - return GNUNET_OK; -} - - -/** - * Extraxt variable-size base32crockford encoded data from request. - * - * Queues an error response to the connection if the parameter is missing - * or the encoding is invalid. - * - * @param connection the MHD connection - * @param param_name the name of the parameter with the key - * @param[out] out_data pointer to allocate buffer and store the result - * @param[out] out_size set to the size of the buffer allocated in @a out_data - * @return - * #GNUNET_YES if the the argument is present - * #GNUNET_NO if the argument is absent or malformed - * #GNUNET_SYSERR on internal error (error response could not be sent) - */ -int -TALER_MINT_mhd_request_var_arg_data (struct MHD_Connection *connection, - const char *param_name, - void **out_data, - size_t *out_size) -{ - const char *str; - size_t slen; - size_t olen; - void *out; - - str = MHD_lookup_connection_value (connection, - MHD_GET_ARGUMENT_KIND, - param_name); - if (NULL == str) - { - return (MHD_NO == - TALER_MINT_reply_arg_missing (connection, param_name)) - ? GNUNET_SYSERR : GNUNET_NO; - } - slen = strlen (str); - olen = (slen * 5) / 8; - out = GNUNET_malloc (olen); - if (GNUNET_OK != - GNUNET_STRINGS_string_to_data (str, - strlen (str), - out, - olen)) - { - GNUNET_free (out); - *out_size = 0; - return (MHD_NO == - TALER_MINT_reply_arg_invalid (connection, param_name)) - ? GNUNET_SYSERR : GNUNET_NO; - } - *out_data = out; - *out_size = olen; - return GNUNET_OK; -} - - /* end of taler-mint-httpd_parsing.c */ diff --git a/src/mint/taler-mint-httpd_parsing.h b/src/mint/taler-mint-httpd_parsing.h index 86205a070..f14090172 100644 --- a/src/mint/taler-mint-httpd_parsing.h +++ b/src/mint/taler-mint-httpd_parsing.h @@ -108,7 +108,19 @@ enum TALER_MINT_JsonNavigationCommand * or -1 for any type). * Params: (int, json_t **) */ - JNAV_RET_TYPED_JSON + JNAV_RET_TYPED_JSON, + + /** + * Return a `struct GNUNET_CRYPTO_rsa_PublicKey` which was + * encoded as variable-size base32crockford encoded data. + */ + JNAV_RET_RSA_PUBLIC_KEY, + + /** + * Return a `struct GNUNET_CRYPTO_rsa_Signature` which was + * encoded as variable-size base32crockford encoded data. + */ + JNAV_RET_RSA_SIGNATURE }; @@ -230,15 +242,34 @@ TALER_MINT_release_parsed_data (struct GNUNET_MINT_ParseFieldSpec *spec); * Generate line in parser specification for JSON array value. * * @param field name of the field + * @param ptraddr address of pointer to initialize (a `void **`) */ -#define TALER_MINT_PARSE_ARRAY(field) { field, NULL, 0, 0, JNAV_RET_TYPED_JSON, JSON_ARRAY } +#define TALER_MINT_PARSE_ARRAY(field,ptraddr) { field, ptraddr, 0, 0, JNAV_RET_TYPED_JSON, JSON_ARRAY } /** * Generate line in parser specification for JSON object value. * * @param field name of the field + * @param ptraddr address of pointer to initialize (a `void **`) */ -#define TALER_MINT_PARSE_OBJECT(field) { field, NULL, 0, 0, JNAV_RET_TYPED_JSON, JSON_OBJECT } +#define TALER_MINT_PARSE_OBJECT(field,ptraddr) { field, ptraddr, 0, 0, JNAV_RET_TYPED_JSON, JSON_OBJECT } + +/** + * Generate line in parser specification for RSA public key. + * + * @param field name of the field + * @param ptraddr address of `struct GNUNET_CRYPTO_rsa_PublicKey *` initialize + */ +#define TALER_MINT_PARSE_RSA_PUBLIC_KEY(field,ptrpk) { field, ptrpk, 0, 0, JNAV_RET_RSA_PUBLIC_KEY, 0 } + +/** + * Generate line in parser specification for RSA public key. + * + * @param field name of the field + * @param ptrsig address of `struct GNUNET_CRYPTO_rsa_Signature *` initialize + */ +#define TALER_MINT_PARSE_RSA_SIGNATURE(field,ptrsig) { field, ptrsig, 0, 0, JNAV_RET_RSA_SIGNATURE, 0 } + /** diff --git a/src/mint/taler-mint-httpd_refresh.c b/src/mint/taler-mint-httpd_refresh.c index 89aff83ab..198ad423e 100644 --- a/src/mint/taler-mint-httpd_refresh.c +++ b/src/mint/taler-mint-httpd_refresh.c @@ -107,9 +107,9 @@ request_json_require_coin_public_info (struct MHD_Connection *connection, struct GNUNET_CRYPTO_rsa_PublicKey *pk; struct GNUNET_MINT_ParseFieldSpec spec[] = { - TALER_MINT_PARSE_FIXED("coin_pub", &r_public_info->coin_pub), - TALER_MINT_PARSE_VARIABLE("denom_sig"), - TALER_MINT_PARSE_VARIABLE("denom_pub"), + TALER_MINT_PARSE_FIXED ("coin_pub", &r_public_info->coin_pub), + TALER_MINT_PARSE_RSA_SIGNATURE ("denom_sig", &sig), + TALER_MINT_PARSE_RSA_PUBLIC_KEY ("denom_pub", &pk), TALER_MINT_PARSE_END }; @@ -118,21 +118,7 @@ request_json_require_coin_public_info (struct MHD_Connection *connection, spec); if (GNUNET_OK != ret) return ret; - sig = GNUNET_CRYPTO_rsa_signature_decode (spec[1].destination, - spec[1].destination_size_out); - pk = GNUNET_CRYPTO_rsa_public_key_decode (spec[2].destination, - spec[2].destination_size_out); - TALER_MINT_release_parsed_data (spec); - if ( (NULL == pk) || - (NULL == sig) ) - { - if (NULL != sig) - GNUNET_CRYPTO_rsa_signature_free (sig); - if (NULL != pk) - GNUNET_CRYPTO_rsa_public_key_free (pk); - // FIXME: send error reply... - return GNUNET_NO; - } + // TALER_MINT_release_parsed_data (spec); r_public_info->denom_sig = sig; r_public_info->denom_pub = pk; return GNUNET_OK; @@ -152,8 +138,8 @@ request_json_require_coin_public_info (struct MHD_Connection *connection, */ static int request_json_check_signature (struct MHD_Connection *connection, - json_t *root, - struct GNUNET_CRYPTO_EddsaPublicKey *pub, + const json_t *root, + const struct GNUNET_CRYPTO_EddsaPublicKey *pub, struct GNUNET_CRYPTO_EccSignaturePurpose *purpose) { struct GNUNET_CRYPTO_EddsaSignature signature; @@ -230,100 +216,38 @@ request_json_check_signature (struct MHD_Connection *connection, /** - * Handle a "/refresh/melt" request + * Handle a "/refresh/melt" request after the first parsing has happened. + * We now need to validate the coins being melted and the session signature + * and then hand things of to execute the melt operation. * - * @param rh context of the handler * @param connection the MHD connection to handle - * @param[IN|OUT] connection_cls the connection's closure (can be updated) - * @param upload_data upload data - * @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data + * @param refresh_session_pub public key of the melt operation + * @param new_denoms array of denomination keys + * @param melt_coins array of coins to melt + * @param melt_sig_json signature affirming the melt operation * @return MHD result code */ -int -TALER_MINT_handler_refresh_melt (struct RequestHandler *rh, - struct MHD_Connection *connection, - void **connection_cls, - const char *upload_data, - size_t *upload_data_size) +static int +handle_refresh_melt_json (struct MHD_Connection *connection, + const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub, + const json_t *new_denoms, + const json_t *melt_coins, + const json_t *melt_sig_json) { - json_t *root; - struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub; int res; - json_t *new_denoms; unsigned int num_new_denoms; unsigned int i; struct GNUNET_CRYPTO_rsa_PublicKey **denom_pubs; - json_t *melt_coins; struct TALER_CoinPublicInfo *coin_public_infos; unsigned int coin_count; struct GNUNET_HashContext *hash_context; struct GNUNET_HashCode melt_hash; struct MintKeyState *key_state; struct RefreshMeltSignatureBody body; - json_t *melt_sig_json; char *buf; size_t buf_size; struct TALER_MINT_DenomKeyIssuePriv *dki; - res = TALER_MINT_parse_post_json (connection, - connection_cls, - upload_data, - upload_data_size, - &root); - if (GNUNET_SYSERR == res) - return MHD_NO; - if ( (GNUNET_NO == res) || (NULL == root) ) - return MHD_YES; - - res = GNUNET_MINT_parse_navigate_json (connection, - root, - JNAV_FIELD, - "session_pub", - JNAV_RET_DATA, - &refresh_session_pub, - sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); - if (GNUNET_SYSERR == res) - return MHD_NO; - if (GNUNET_NO == res) - return MHD_YES; - res = GNUNET_MINT_parse_navigate_json (connection, - root, - JNAV_FIELD, - "new_denoms", - JNAV_RET_TYPED_JSON, - JSON_ARRAY, - &new_denoms); - if (GNUNET_SYSERR == res) - return MHD_NO; - if (GNUNET_NO == res) - return MHD_YES; - - res = GNUNET_MINT_parse_navigate_json (connection, - root, - JNAV_FIELD, - "melt_coins", - JNAV_RET_TYPED_JSON, - JSON_ARRAY, - &melt_coins); - if (GNUNET_OK != res) - { - // FIXME: leaks! - return res; - } - - melt_sig_json = json_object_get (root, - "melt_signature"); - if (NULL == melt_sig_json) - { - return TALER_MINT_reply_json_pack (connection, - MHD_HTTP_BAD_REQUEST, - "{s:s}", - "error", - "melt_signature missing"); - } - - - num_new_denoms = json_array_size (new_denoms); denom_pubs = GNUNET_malloc (num_new_denoms * @@ -331,8 +255,7 @@ TALER_MINT_handler_refresh_melt (struct RequestHandler *rh, for (i=0;i<num_new_denoms;i++) { - res = GNUNET_MINT_parse_navigate_json (connection, root, - JNAV_FIELD, "new_denoms", + res = GNUNET_MINT_parse_navigate_json (connection, new_denoms, JNAV_INDEX, (int) i, JNAV_RET_DATA_VAR, &buf, @@ -380,7 +303,7 @@ TALER_MINT_handler_refresh_melt (struct RequestHandler *rh, (res = check_confirm_signature (connection, json_array_get (melt_coins, i), &coin_public_infos[i].coin_pub, - &refresh_session_pub))) + refresh_session_pub))) { GNUNET_break (GNUNET_SYSERR != res); // FIXME: leaks! @@ -439,7 +362,7 @@ TALER_MINT_handler_refresh_melt (struct RequestHandler *rh, if (GNUNET_OK != (res = request_json_check_signature (connection, melt_sig_json, - &refresh_session_pub, + refresh_session_pub, &body.purpose))) { // FIXME: generate proper error reply @@ -448,7 +371,7 @@ TALER_MINT_handler_refresh_melt (struct RequestHandler *rh, res = TALER_MINT_db_execute_refresh_melt (connection, - &refresh_session_pub, + refresh_session_pub, num_new_denoms, denom_pubs, coin_count, @@ -459,6 +382,66 @@ TALER_MINT_handler_refresh_melt (struct RequestHandler *rh, /** + * Handle a "/refresh/melt" request. Parses the request into the JSON + * components and then hands things of to #handle_referesh_melt_json() + * to validate the melted coins, the signature and execute the melt. + * + * @param rh context of the handler + * @param connection the MHD connection to handle + * @param[IN|OUT] connection_cls the connection's closure (can be updated) + * @param upload_data upload data + * @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data + * @return MHD result code + */ +int +TALER_MINT_handler_refresh_melt (struct RequestHandler *rh, + struct MHD_Connection *connection, + void **connection_cls, + const char *upload_data, + size_t *upload_data_size) +{ + json_t *root; + json_t *new_denoms; + json_t *melt_coins; + json_t *melt_sig_json; + struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub; + int res; + struct GNUNET_MINT_ParseFieldSpec spec[] = { + TALER_MINT_PARSE_FIXED ("session_pub", &refresh_session_pub), + TALER_MINT_PARSE_ARRAY ("new_denoms", &new_denoms), + TALER_MINT_PARSE_ARRAY ("melt_coins", &melt_coins), + TALER_MINT_PARSE_ARRAY ("melt_signature", &melt_sig_json), + TALER_MINT_PARSE_END + }; + + res = TALER_MINT_parse_post_json (connection, + connection_cls, + upload_data, + upload_data_size, + &root); + if (GNUNET_SYSERR == res) + return MHD_NO; + if ( (GNUNET_NO == res) || (NULL == root) ) + return MHD_YES; + + res = TALER_MINT_parse_json_data (connection, + root, + spec); + if (GNUNET_SYSERR == res) + return MHD_NO; + if (GNUNET_NO == res) + return MHD_YES; + res = handle_refresh_melt_json (connection, + &refresh_session_pub, + new_denoms, + melt_coins, + melt_sig_json); + TALER_MINT_release_parsed_data (spec); + return res; +} + + +/** * Handle a "/refresh/commit" request * * @param rh context of the handler |