diff options
| author | Christian Grothoff <christian@grothoff.org> | 2015-03-10 17:00:12 +0100 | 
|---|---|---|
| committer | Christian Grothoff <christian@grothoff.org> | 2015-03-10 17:00:12 +0100 | 
| commit | 7e26ae385896a974d8a90234a155c32b383e70f7 (patch) | |
| tree | 1bbcf3e317744c9fa024bba5a6e46c84520dc9e5 | |
| parent | e3b8f5117e8028f3183871ab0efb0c6f2ff959eb (diff) | |
clean up refresh logic and use of signatures
| -rw-r--r-- | src/include/taler_signatures.h | 48 | ||||
| -rw-r--r-- | src/mint/taler-mint-httpd_refresh.c | 293 | ||||
| -rw-r--r-- | src/mint/taler-mint-httpd_responses.c | 7 | 
3 files changed, 145 insertions, 203 deletions
| diff --git a/src/include/taler_signatures.h b/src/include/taler_signatures.h index 9e3068a7..b1b57823 100644 --- a/src/include/taler_signatures.h +++ b/src/include/taler_signatures.h @@ -65,7 +65,7 @@   * Signature where the refresh session confirms   * the commits.   */ -#define TALER_SIGNATURE_REFRESH_MELT 6 +#define TALER_SIGNATURE_REFRESH_MELT_SESSION 6  /**   * Signature where the mint (current signing key) @@ -221,7 +221,7 @@ struct TALER_DepositConfirmation    struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub;    /** -   * The Merachant's public key. +   * The Merchant's public key.     */    struct GNUNET_CRYPTO_EddsaPublicKey merchant; @@ -232,7 +232,7 @@ struct TALER_DepositConfirmation   * Message signed by a coin to indicate that the coin should   * be melted.   */ -struct RefreshMeltSignatureBody +struct RefreshMeltCoinSignature  {    /**     * Purpose is #TALER_SIGNATURE_REFRESH_MELT_COIN. @@ -245,42 +245,46 @@ struct RefreshMeltSignatureBody    struct GNUNET_HashCode melt_hash;    /** -   * Signature of the client over the melt request (thereby -   * indirectly including all of the information the client -   * sent). -   */ -  struct GNUNET_CRYPTO_EddsaSignature melt_client_signature; - -  /** -   * Public key of the refresh session for which -   * @e melt_client_signature must be a valid signature. -   */ -  struct GNUNET_CRYPTO_EddsaPublicKey session_key; - -  /**     * How much of the value of the coin should be melted?     * This amount includes the fees, so the final amount contributed     * to the melt is this value minus the fee for melting the coin.     */    struct TALER_AmountNBO amount; + +  /** +   * The coin's public key. +   */ +  struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub;  };  /** - * Message signed during melting committing the client to the - * hashed inputs. + * Message signed by a coin to indicate that the coin should + * be melted.   */ -struct RefreshCommitSignatureBody +struct RefreshMeltSessionSignature  {    /** -   * Purpose is #TALER_SIGNATURE_REFRESH_MELT. +   * Purpose is #TALER_SIGNATURE_REFRESH_MELT_SESSION     */    struct GNUNET_CRYPTO_EccSignaturePurpose purpose;    /** -   * Session state the client commits itself to. +   * Which melting operation should the coin become a part of. +   */ +  struct GNUNET_HashCode melt_hash; + +  /** +   * Public key of the refresh session for which +   * @e melt_client_signature must be a valid signature.     */ -  struct GNUNET_HashCode commit_hash; +  struct GNUNET_CRYPTO_EddsaPublicKey session_key; + +  /** +   * What is the total value of the coins created during the +   * refresh, excluding fees? +   */ +  struct TALER_AmountNBO amount;  }; diff --git a/src/mint/taler-mint-httpd_refresh.c b/src/mint/taler-mint-httpd_refresh.c index 6c3cbbc7..d36e4208 100644 --- a/src/mint/taler-mint-httpd_refresh.c +++ b/src/mint/taler-mint-httpd_refresh.c @@ -36,109 +36,6 @@  /** - * 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 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 - *         #GNUNET_NO if the signature was invalid - *         #GNUNET_SYSERR on internal error - */ -static int -request_json_check_signature (struct MHD_Connection *connection, -                              const json_t *json_sig, -                              const struct GNUNET_CRYPTO_EddsaPublicKey *pub, -                              const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose) -{ -  struct GNUNET_CRYPTO_EddsaSignature signature; -  int size; -  uint32_t purpose_num; -  int res; -  json_t *el; - -  /* 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, -                                         json_sig, -                                         JNAV_FIELD, -                                         "purpose", -                                         JNAV_RET_TYPED_JSON, -                                         JSON_INTEGER, -                                         &el); - -  if (GNUNET_OK != res) -    return res; - -  purpose_num = json_integer_value (el); - -  if (purpose_num != ntohl (purpose->purpose)) -  { -    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, -                                         json_sig, -                                         JNAV_FIELD, "size", -                                         JNAV_RET_TYPED_JSON, -                                         JSON_INTEGER, -                                         &el); - -  if (GNUNET_OK != res) -    return res; - -  size = json_integer_value (el); - -  if (size != ntohl (purpose->size)) -  { -    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)"); -  } - -  if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (purpose_num, -                                               purpose, -                                               &signature, -                                               pub)) -  { -    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, -                "signature invalid (did not verify)\n"); -    return TALER_MINT_reply_json_pack (connection, -                                       MHD_HTTP_UNAUTHORIZED, -                                       "{s:s}", -                                       "error", -                                       "invalid signature (verification)"); -  } - -  return GNUNET_OK; -} - - -/**   * 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. @@ -150,7 +47,7 @@ request_json_check_signature (struct MHD_Connection *connection,   * @param coin_count number of coins to be melted, size of y-dimension of @commit_coin array   * @param coin_public_infos array with @a coin_count entries about the coins   * @param coin_melt_details array with @a coin_count entries with melting details - * @param melt_sig_json signature affirming the overall melt operation + * @param commit_hash hash over the data that the client commits to   * @param commit_client_sig signature of the client over this commitment   * @param kappa size of x-dimension of @commit_coin and @commit_link arrays   * @param commit_coin 2d array of coin commitments (what the mint is to sign @@ -168,18 +65,17 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,                              unsigned int coin_count,                              struct TALER_CoinPublicInfo *coin_public_infos,                              const struct MeltDetails *coin_melt_details, -                            const json_t *melt_sig_json, +                            const struct GNUNET_HashCode *commit_hash,                              const struct GNUNET_CRYPTO_EddsaSignature *commit_client_sig,                              unsigned int kappa,                              struct RefreshCommitCoin *const* commit_coin,                              struct RefreshCommitLink *const* commit_link)  { -  int res;    unsigned int i;    struct GNUNET_HashContext *hash_context;    struct GNUNET_HashCode melt_hash; -  struct RefreshMeltSignatureBody body; +  struct RefreshMeltSessionSignature body;    char *buf;    size_t buf_size;    struct MintKeyState *key_state; @@ -207,18 +103,26 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,                                       sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));    GNUNET_CRYPTO_hash_context_finish (hash_context,                                       &melt_hash); +  // FIXME: what about the `commit_hash`? -  body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT); -  body.purpose.size = htonl (sizeof (struct RefreshMeltSignatureBody)); +  body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_SESSION); +  body.purpose.size = htonl (sizeof (struct RefreshMeltSessionSignature));    body.melt_hash = melt_hash;    body.amount = TALER_amount_hton (coin_melt_details->melt_amount); -  if (GNUNET_OK != -      (res = request_json_check_signature (connection, -                                           melt_sig_json, -                                           refresh_session_pub, -                                           &body.purpose))) -    return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; +  if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_REFRESH_MELT_SESSION, +                                               &body.purpose, +                                               commit_client_sig, +                                               refresh_session_pub)) +  { +    GNUNET_log (GNUNET_ERROR_TYPE_WARNING, +                "signature invalid (did not verify)\n"); +    return TALER_MINT_reply_json_pack (connection, +                                       MHD_HTTP_UNAUTHORIZED, +                                       "{s:s}", +                                       "error", +                                       "invalid signature (verification)"); +  }    // FIXME: badness, use proper way to set to zero...    key_state = TALER_MINT_key_state_acquire (); @@ -276,15 +180,9 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,  /** - * Extract public coin information from a JSON object and verify - * that the signature shows that this coin is to be melted into - * the given @a session_pub melting session, and that this is - * a valid coin (we know the denomination key and the signature - * on it is valid).  Essentially, this does all of the per-coin - * checks that can be done before the transaction starts. + * Extract public coin information from a JSON object.   *   * @param connection the connection to send error responses to - * @param session_pub public key of the session the coin is melted into   * @param coin_info the JSON object to extract the coin info from   * @param r_public_info[OUT] set to the coin's public information   * @param r_melt_detail[OUT] set to details about the coin's melting permission (if valid) @@ -293,19 +191,15 @@ handle_refresh_melt_binary (struct MHD_Connection *connection,   *         #GNUNET_SYSERR on internal error   */  static int -get_and_verify_coin_public_info (struct MHD_Connection *connection, -                                 const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub, -                                 json_t *coin_info, -                                 struct TALER_CoinPublicInfo *r_public_info, -                                 struct MeltDetails *r_melt_detail) +get_coin_public_info (struct MHD_Connection *connection, +                      json_t *coin_info, +                      struct TALER_CoinPublicInfo *r_public_info, +                      struct MeltDetails *r_melt_detail)  {    int ret;    struct GNUNET_CRYPTO_EcdsaSignature melt_sig;    struct GNUNET_CRYPTO_rsa_Signature *sig;    struct GNUNET_CRYPTO_rsa_PublicKey *pk; -  struct RefreshMeltConfirmSignRequestBody body; -  struct MintKeyState *key_state; -  struct TALER_MINT_DenomKeyIssuePriv *dki;    struct TALER_Amount amount;    struct GNUNET_MINT_ParseFieldSpec spec[] = {      TALER_MINT_PARSE_FIXED ("coin_pub", &r_public_info->coin_pub), @@ -316,6 +210,7 @@ get_and_verify_coin_public_info (struct MHD_Connection *connection,      TALER_MINT_PARSE_END    }; +  memset (&amount, 0, sizeof (amount)); // FIXME: #3636!    ret = TALER_MINT_parse_json_data (connection,                                      coin_info,                                      spec); @@ -323,17 +218,68 @@ get_and_verify_coin_public_info (struct MHD_Connection *connection,      return ret;    /* FIXME: include amount of coin value to be melted here (#3636!) and      in what we return!? */ -  memset (&amount, 0, sizeof (amount)); // FIXME: #3636! -  body.purpose.size = htonl (sizeof (struct RefreshMeltConfirmSignRequestBody)); -  body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_CONFIRM); -  body.session_pub = *session_pub; + +  /* check mint signature on the coin */ +  r_public_info->denom_sig = sig; +  r_public_info->denom_pub = pk;    if (GNUNET_OK != -      GNUNET_CRYPTO_ecdsa_verify (TALER_SIGNATURE_REFRESH_MELT_CONFIRM, +      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; +  } +  r_melt_detail->melt_sig = melt_sig; +  r_melt_detail->melt_amount = amount; +  TALER_MINT_release_parsed_data (spec); +  return GNUNET_OK; +} + + +/** + * Verify that the signature shows that this coin is to be melted into + * the given @a session_pub melting session, and that this is a valid + * coin (we know the denomination key and the signature on it is + * valid).  Essentially, this does all of the per-coin checks that can + * be done before the transaction starts. + * + * @param connection the connection to send error responses to + * @param melt_hash hash over refresh session the coin is melted into + * @param r_public_info the coin's public information + * @param r_melt_detail details about the coin's melting permission (if valid) + * @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 +verify_coin_public_info (struct MHD_Connection *connection, +                         const struct GNUNET_HashCode *melt_hash, +                         const struct TALER_CoinPublicInfo *r_public_info, +                         const struct MeltDetails *r_melt_detail) +{ +  struct RefreshMeltCoinSignature body; +  struct MintKeyState *key_state; +  struct TALER_MINT_DenomKeyIssuePriv *dki; + +  /* FIXME: include amount of coin value to be melted here (#3636!) and +    in what we return!? */ +  body.purpose.size = htonl (sizeof (struct RefreshMeltCoinSignature)); +  body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_COIN); +  body.melt_hash = *melt_hash; +  body.amount = TALER_amount_hton (r_melt_detail->melt_amount); +  body.coin_pub = r_public_info->coin_pub; +  if (GNUNET_OK != +      GNUNET_CRYPTO_ecdsa_verify (TALER_SIGNATURE_REFRESH_MELT_COIN,                                    &body.purpose, -                                  &melt_sig, +                                  &r_melt_detail->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, @@ -344,7 +290,7 @@ get_and_verify_coin_public_info (struct MHD_Connection *connection,    }    key_state = TALER_MINT_key_state_acquire ();    dki = TALER_MINT_get_denom_key (key_state, -                                  pk); +                                  r_public_info->denom_pub);    /* FIXME: need to check if denomination key is still       valid for issuing! (#3634) */    if (NULL == dki) @@ -355,25 +301,6 @@ get_and_verify_coin_public_info (struct MHD_Connection *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; -  } -  r_melt_detail->melt_sig = melt_sig; -  r_melt_detail->melt_amount = amount;    return GNUNET_OK;  } @@ -478,9 +405,9 @@ handle_refresh_melt_json (struct MHD_Connection *connection,    unsigned int coin_count;    struct GNUNET_HashCode commit_hash;    struct GNUNET_HashContext *hash_context; -  struct RefreshCommitSignatureBody body;    struct RefreshCommitCoin *commit_coin[kappa];    struct RefreshCommitLink *commit_link[kappa]; +  const struct GNUNET_CRYPTO_EddsaSignature commit_client_sig;    num_new_denoms = json_array_size (new_denoms);    denom_pubs = GNUNET_malloc (num_new_denoms * @@ -509,11 +436,10 @@ handle_refresh_melt_json (struct MHD_Connection *connection,    for (i=0;i<coin_count;i++)    {      /* decode JSON data on coin to melt */ -    res = get_and_verify_coin_public_info (connection, -                                           refresh_session_pub, -                                           json_array_get (melt_coins, i), -                                           &coin_public_infos[i], -                                           &coin_melt_details[i]); +    res = get_coin_public_info (connection, +                                json_array_get (melt_coins, i), +                                &coin_public_infos[i], +                                &coin_melt_details[i]);      if (GNUNET_OK != res)      {        for (j=0;j<i;j++) @@ -635,24 +561,34 @@ handle_refresh_melt_json (struct MHD_Connection *connection,    }    GNUNET_CRYPTO_hash_context_finish (hash_context, &commit_hash); -  /* verify commit signature */ -  body.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT); -  body.purpose.size = htonl (sizeof (struct RefreshCommitSignatureBody)); -  body.commit_hash = commit_hash; -  if (GNUNET_OK != -      (res = request_json_check_signature (connection, -                                           commit_signature, -                                           refresh_session_pub, -                                           &body.purpose))) +  res = GNUNET_MINT_parse_navigate_json (connection, +                                         commit_signature, +                                         JNAV_FIELD, +                                         "sig", +                                         JNAV_RET_DATA, +                                         &commit_client_sig, +                                         sizeof (struct GNUNET_CRYPTO_EddsaSignature)); + +  if (GNUNET_OK != res) +    return (GNUNET_NO == res) ? MHD_YES : MHD_NO; + + +  for (i=0;i<coin_count;i++)    { -    free_commit_coins (commit_coin, kappa, num_newcoins); -    free_commit_links (commit_link, kappa, num_oldcoins); -    return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES; +    /* verify signatures ons coin to melt */ +    res = verify_coin_public_info (connection, +                                   &commit_hash, +                                   &coin_public_infos[i], +                                   &coin_melt_details[i]); +    if (GNUNET_OK != res) +    { +      res = (GNUNET_NO == res) ? MHD_YES : MHD_NO; +      goto cleanup; +    }    }    /* execute commit */ -  /* FIXME: we must also store the signature! (#3635) */    res = handle_refresh_melt_binary (connection,                                      refresh_session_pub,                                      num_new_denoms, @@ -660,11 +596,12 @@ handle_refresh_melt_json (struct MHD_Connection *connection,                                      coin_count,                                      coin_public_infos,                                      coin_melt_details, -                                    melt_sig_json, -                                    NULL /* FIXME: 3635! */, +                                    &commit_hash, +                                    &commit_client_sig,                                      kappa,                                      commit_coin,                                      commit_link); + cleanup:    free_commit_coins (commit_coin, kappa, num_newcoins);    free_commit_links (commit_link, kappa, num_oldcoins);    for (j=0;j<coin_count;j++) diff --git a/src/mint/taler-mint-httpd_responses.c b/src/mint/taler-mint-httpd_responses.c index 83c81e80..2faeb5ca 100644 --- a/src/mint/taler-mint-httpd_responses.c +++ b/src/mint/taler-mint-httpd_responses.c @@ -355,15 +355,16 @@ compile_transaction_history (const struct TALER_MINT_DB_TransactionList *tl)        }      case TALER_MINT_DB_TT_REFRESH_MELT:        { -        struct RefreshMeltSignatureBody ms; +        struct RefreshMeltCoinSignature ms;          const struct RefreshMelt *melt = pos->details.melt;          type = "melt";          value = melt->amount; -        ms.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT); -        ms.purpose.size = htonl (sizeof (struct RefreshMeltSignatureBody)); +        ms.purpose.purpose = htonl (TALER_SIGNATURE_REFRESH_MELT_COIN); +        ms.purpose.size = htonl (sizeof (struct RefreshMeltCoinSignature));          ms.melt_hash = melt->melt_hash;          ms.amount = TALER_amount_hton (melt->amount); +        ms.coin_pub = melt->coin.coin_pub;          transaction = TALER_JSON_from_ecdsa_sig (&ms.purpose,                                                   &melt->coin_sig);        } | 
