From 1e3e6fa5990eb2504a69279039ee776a19ff1ec2 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Thu, 29 Jan 2015 16:26:58 +0100 Subject: [PATCH] finish cleanup of /refresh/melt parsing --- src/mint/taler-mint-httpd_parsing.h | 2 - src/mint/taler-mint-httpd_refresh.c | 460 +++++++++++++++------------- 2 files changed, 241 insertions(+), 221 deletions(-) diff --git a/src/mint/taler-mint-httpd_parsing.h b/src/mint/taler-mint-httpd_parsing.h index f14090172..2a2d54ea8 100644 --- a/src/mint/taler-mint-httpd_parsing.h +++ b/src/mint/taler-mint-httpd_parsing.h @@ -270,8 +270,6 @@ TALER_MINT_release_parsed_data (struct GNUNET_MINT_ParseFieldSpec *spec); */ #define TALER_MINT_PARSE_RSA_SIGNATURE(field,ptrsig) { field, ptrsig, 0, 0, JNAV_RET_RSA_SIGNATURE, 0 } - - /** * Generate line in parser specification indicating the end of the spec. */ diff --git a/src/mint/taler-mint-httpd_refresh.c b/src/mint/taler-mint-httpd_refresh.c index 198ad423e..0abc82eb7 100644 --- a/src/mint/taler-mint-httpd_refresh.c +++ b/src/mint/taler-mint-httpd_refresh.c @@ -43,93 +43,14 @@ #include "taler-mint-httpd_keystate.h" -static int -check_confirm_signature (struct MHD_Connection *connection, - json_t *coin_info, - const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub, - const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub) -{ - struct RefreshMeltConfirmSignRequestBody body; - struct GNUNET_CRYPTO_EcdsaSignature sig; - int res; - - body.purpose.size = htonl (sizeof (struct RefreshMeltConfirmSignRequestBody)); - body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_CONFIRM); - body.session_pub = *session_pub; - - res = GNUNET_MINT_parse_navigate_json (connection, coin_info, - JNAV_FIELD, "confirm_sig", - JNAV_RET_DATA, - &sig, - sizeof (struct GNUNET_CRYPTO_EcdsaSignature)); - - if (GNUNET_OK != res) - { - GNUNET_break (GNUNET_SYSERR != res); - return res; - } - - if (GNUNET_OK != - GNUNET_CRYPTO_ecdsa_verify (TALER_SIGNATURE_REFRESH_MELT_CONFIRM, - &body.purpose, - &sig, - coin_pub)) - { - if (MHD_YES != - TALER_MINT_reply_json_pack (connection, - MHD_HTTP_UNAUTHORIZED, - "{s:s}", - "error", "signature invalid")) - return GNUNET_SYSERR; - return GNUNET_NO; - } - - return GNUNET_OK; -} - - /** - * Extract public coin information from a JSON object. - * - * @param connection the connection to send error responses to - * @param root the JSON object to extract the coin info from - * @return #GNUNET_YES if coin public info in JSON was valid - * #GNUNET_NO JSON was invalid, response was generated - * #GNUNET_SYSERR on internal error - */ -static int -request_json_require_coin_public_info (struct MHD_Connection *connection, - json_t *root, - struct TALER_CoinPublicInfo *r_public_info) -{ - int ret; - struct GNUNET_CRYPTO_rsa_Signature *sig; - 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_RSA_SIGNATURE ("denom_sig", &sig), - TALER_MINT_PARSE_RSA_PUBLIC_KEY ("denom_pub", &pk), - TALER_MINT_PARSE_END - }; - - ret = TALER_MINT_parse_json_data (connection, - root, - spec); - if (GNUNET_OK != ret) - return ret; - // TALER_MINT_release_parsed_data (spec); - r_public_info->denom_sig = sig; - r_public_info->denom_pub = pk; - return GNUNET_OK; -} - - -/** - * Verify a signature that is encoded in a JSON object + * Verify a signature that is encoded in a JSON object. Extracts + * the signature and its associated purpose and checks that it + * matches the specified @a purpose and @a pub public key. Any + * errors are reported via appropriate response messages. * * @param connection the connection to send errors to - * @param root the JSON object with the signature + * @param json_sig the JSON object with the signature * @param the public key that the signature was created with * @param purpose the signed message * @return #GNUNET_YES if the signature was valid @@ -138,9 +59,9 @@ request_json_require_coin_public_info (struct MHD_Connection *connection, */ static int request_json_check_signature (struct MHD_Connection *connection, - const json_t *root, + const json_t *json_sig, const struct GNUNET_CRYPTO_EddsaPublicKey *pub, - struct GNUNET_CRYPTO_EccSignaturePurpose *purpose) + const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose) { struct GNUNET_CRYPTO_EddsaSignature signature; int size; @@ -148,20 +69,25 @@ request_json_check_signature (struct MHD_Connection *connection, int res; json_t *el; - res = GNUNET_MINT_parse_navigate_json (connection, root, - JNAV_FIELD, "sig", - JNAV_RET_DATA, - &signature, - sizeof (struct GNUNET_CRYPTO_EddsaSignature)); + /* TODO: use specification array to simplify the parsing! */ + res = GNUNET_MINT_parse_navigate_json (connection, + json_sig, + JNAV_FIELD, + "sig", + JNAV_RET_DATA, + &signature, + sizeof (struct GNUNET_CRYPTO_EddsaSignature)); if (GNUNET_OK != res) return res; - res = GNUNET_MINT_parse_navigate_json (connection, root, - JNAV_FIELD, "purpose", - JNAV_RET_TYPED_JSON, - JSON_INTEGER, - &el); + res = GNUNET_MINT_parse_navigate_json (connection, + json_sig, + JNAV_FIELD, + "purpose", + JNAV_RET_TYPED_JSON, + JSON_INTEGER, + &el); if (GNUNET_OK != res) return res; @@ -170,18 +96,20 @@ request_json_check_signature (struct MHD_Connection *connection, if (purpose_num != ntohl (purpose->purpose)) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "signature invalid (purpose wrong)\n"); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "signature invalid (purpose wrong)\n"); return TALER_MINT_reply_json_pack (connection, MHD_HTTP_BAD_REQUEST, "{s:s}", "error", "signature invalid (purpose)"); } - res = GNUNET_MINT_parse_navigate_json (connection, root, - JNAV_FIELD, "size", - JNAV_RET_TYPED_JSON, - JSON_INTEGER, - &el); + res = GNUNET_MINT_parse_navigate_json (connection, + json_sig, + JNAV_FIELD, "size", + JNAV_RET_TYPED_JSON, + JSON_INTEGER, + &el); if (GNUNET_OK != res) return res; @@ -190,12 +118,14 @@ request_json_check_signature (struct MHD_Connection *connection, if (size != ntohl (purpose->size)) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "signature invalid (size wrong)\n"); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "signature invalid (size wrong)\n"); return TALER_MINT_reply_json_pack (connection, MHD_HTTP_BAD_REQUEST, GNUNET_NO, GNUNET_SYSERR, "{s:s}", - "error", "signature invalid (size)"); + "error", + "signature invalid (size)"); } if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (purpose_num, @@ -203,7 +133,8 @@ request_json_check_signature (struct MHD_Connection *connection, &signature, pub)) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "signature invalid (did not verify)\n"); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "signature invalid (did not verify)\n"); return TALER_MINT_reply_json_pack (connection, MHD_HTTP_UNAUTHORIZED, "{s:s}", @@ -216,7 +147,7 @@ request_json_check_signature (struct MHD_Connection *connection, /** - * Handle a "/refresh/melt" request after the first parsing has happened. + * Handle a "/refresh/melt" request after the main JSON 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. * @@ -228,114 +159,21 @@ request_json_check_signature (struct MHD_Connection *connection, * @return MHD result code */ 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) +handle_refresh_melt_binary (struct MHD_Connection *connection, + const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub, + unsigned int num_new_denoms, + struct GNUNET_CRYPTO_rsa_PublicKey *const*denom_pubs, + unsigned int coin_count, + struct TALER_CoinPublicInfo *coin_public_infos, + const json_t *melt_sig_json) { int res; - unsigned int num_new_denoms; unsigned int i; - struct GNUNET_CRYPTO_rsa_PublicKey **denom_pubs; - 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; char *buf; size_t buf_size; - struct TALER_MINT_DenomKeyIssuePriv *dki; - - num_new_denoms = json_array_size (new_denoms); - - denom_pubs = GNUNET_malloc (num_new_denoms * - sizeof (struct GNUNET_CRYPTO_rsa_PublicKey *)); - - for (i=0;icoin_pub), + TALER_MINT_PARSE_RSA_SIGNATURE ("denom_sig", &sig), + TALER_MINT_PARSE_RSA_PUBLIC_KEY ("denom_pub", &pk), + TALER_MINT_PARSE_FIXED ("confirm_sig", &melt_sig), + TALER_MINT_PARSE_END + }; + + ret = TALER_MINT_parse_json_data (connection, + coin_info, + spec); + if (GNUNET_OK != ret) + return ret; + /* TODO: include amount of coin value to be melted here!? */ + body.purpose.size = htonl (sizeof (struct RefreshMeltConfirmSignRequestBody)); + body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_CONFIRM); + body.session_pub = *session_pub; + if (GNUNET_OK != + GNUNET_CRYPTO_ecdsa_verify (TALER_SIGNATURE_REFRESH_MELT_CONFIRM, + &body.purpose, + &melt_sig, + &r_public_info->coin_pub)) + { + TALER_MINT_release_parsed_data (spec); + if (MHD_YES != + TALER_MINT_reply_json_pack (connection, + MHD_HTTP_UNAUTHORIZED, + "{s:s}", + "error", "signature invalid")) + return GNUNET_SYSERR; + return GNUNET_NO; + } + key_state = TALER_MINT_key_state_acquire (); + dki = TALER_MINT_get_denom_key (key_state, + pk); + /* FIXME: need to check if denomination key is still + valid for issuing! (#3634) */ + if (NULL == dki) + { + TALER_MINT_key_state_release (key_state); + LOG_WARNING ("Unknown denomination key in /refresh/melt request\n"); + return TALER_MINT_reply_arg_invalid (connection, + "denom_pub"); + } + TALER_MINT_key_state_release (key_state); + + /* check mint signature on the coin */ + r_public_info->denom_sig = sig; + r_public_info->denom_pub = pk; + if (GNUNET_OK != + TALER_test_coin_valid (r_public_info)) + { + TALER_MINT_release_parsed_data (spec); + r_public_info->denom_sig = NULL; + r_public_info->denom_pub = NULL; + return (MHD_YES == + TALER_MINT_reply_json_pack (connection, + MHD_HTTP_NOT_FOUND, + "{s:s}", + "error", "coin invalid")) + ? GNUNET_NO : GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +/** + * 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. This function + * parses the JSON arrays and then passes processing on to + * #handle_refresh_melt_binary(). + * + * @param connection the MHD connection to handle + * @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 + */ +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) +{ + int res; + unsigned int i; + unsigned int j; + struct GNUNET_CRYPTO_rsa_PublicKey **denom_pubs; + unsigned int num_new_denoms; + struct TALER_CoinPublicInfo *coin_public_infos; + unsigned int coin_count; + + num_new_denoms = json_array_size (new_denoms); + denom_pubs = GNUNET_malloc (num_new_denoms * + sizeof (struct GNUNET_CRYPTO_rsa_PublicKey *)); + for (i=0;i