From e200e860321abdff235863bd83e663ae57cf037a Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Tue, 22 Mar 2022 02:33:51 +0100 Subject: implement helper functions for p2p signatures, clean up existing signature logic --- src/util/wallet_signatures.c | 703 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 703 insertions(+) (limited to 'src/util/wallet_signatures.c') diff --git a/src/util/wallet_signatures.c b/src/util/wallet_signatures.c index ef8870442..30903c6b7 100644 --- a/src/util/wallet_signatures.c +++ b/src/util/wallet_signatures.c @@ -23,6 +23,93 @@ #include "taler_signatures.h" +/** + * @brief Format used to generate the signature on a request to deposit + * a coin into the account of a merchant. + */ +struct TALER_DepositRequestPS +{ + /** + * Purpose must be #TALER_SIGNATURE_WALLET_COIN_DEPOSIT. + * Used for an EdDSA signature with the `struct TALER_CoinSpendPublicKeyP`. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Hash over the contract for which this deposit is made. + */ + struct TALER_PrivateContractHashP h_contract_terms GNUNET_PACKED; + + /** + * Hash over the age commitment that went into the coin. Maybe all zero, if + * age commitment isn't applicable to the denomination. + */ + struct TALER_AgeCommitmentHash h_age_commitment GNUNET_PACKED; + + /** + * Hash over extension attributes shared with the exchange. + */ + struct TALER_ExtensionContractHashP h_extensions GNUNET_PACKED; + + /** + * Hash over the wiring information of the merchant. + */ + struct TALER_MerchantWireHashP h_wire GNUNET_PACKED; + + /** + * Hash over the denomination public key used to sign the coin. + */ + struct TALER_DenominationHashP h_denom_pub GNUNET_PACKED; + + /** + * Time when this request was generated. Used, for example, to + * assess when (roughly) the income was achieved for tax purposes. + * Note that the Exchange will only check that the timestamp is not "too + * far" into the future (i.e. several days). The fact that the + * timestamp falls within the validity period of the coin's + * denomination key is irrelevant for the validity of the deposit + * request, as obviously the customer and merchant could conspire to + * set any timestamp. Also, the Exchange must accept very old deposit + * requests, as the merchant might have been unable to transmit the + * deposit request in a timely fashion (so back-dating is not + * prevented). + */ + struct GNUNET_TIME_TimestampNBO wallet_timestamp; + + /** + * How much time does the merchant have to issue a refund request? + * Zero if refunds are not allowed. After this time, the coin + * cannot be refunded. + */ + struct GNUNET_TIME_TimestampNBO refund_deadline; + + /** + * Amount to be deposited, including deposit fee charged by the + * exchange. This is the total amount that the coin's value at the exchange + * will be reduced by. + */ + struct TALER_AmountNBO amount_with_fee; + + /** + * Depositing fee charged by the exchange. This must match the Exchange's + * denomination key's depositing fee. If the client puts in an + * invalid deposit fee (too high or too low) that does not match the + * Exchange's denomination key, the deposit operation is invalid and + * will be rejected by the exchange. The @e amount_with_fee minus the + * @e deposit_fee is the amount that will be transferred to the + * account identified by @e h_wire. + */ + struct TALER_AmountNBO deposit_fee; + + /** + * The Merchant's public key. Allows the merchant to later refund + * the transaction or to inquire about the wire transfer identifier. + */ + struct TALER_MerchantPublicKeyP merchant; + +}; + + void TALER_wallet_deposit_sign ( const struct TALER_Amount *amount, @@ -116,6 +203,41 @@ TALER_wallet_deposit_verify ( } +/** + * @brief Format used for to allow the wallet to authenticate + * link data provided by the exchange. + */ +struct TALER_LinkDataPS +{ + + /** + * Purpose must be #TALER_SIGNATURE_WALLET_COIN_LINK. + * Used with an EdDSA signature of a `struct TALER_CoinPublicKeyP`. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Hash of the denomination public key of the new coin. + */ + struct TALER_DenominationHashP h_denom_pub; + + /** + * Transfer public key (for which the private key was not revealed) + */ + struct TALER_TransferPublicKeyP transfer_pub; + + /** + * Hash of the age commitment, if applicable. Can be all zero + */ + struct TALER_AgeCommitmentHash h_age_commitment; + + /** + * Hash of the blinded new coin. + */ + struct TALER_BlindedCoinHashP coin_envelope_hash; +}; + + void TALER_wallet_link_sign (const struct TALER_DenominationHashP *h_denom_pub, const struct TALER_TransferPublicKeyP *transfer_pub, @@ -161,6 +283,32 @@ TALER_wallet_link_verify ( } +/** + * Signed data to request that a coin should be refunded as part of + * the "emergency" /recoup protocol. The refund will go back to the bank + * account that created the reserve. + */ +struct TALER_RecoupRequestPS +{ + /** + * Purpose is #TALER_SIGNATURE_WALLET_COIN_RECOUP + * or #TALER_SIGNATURE_WALLET_COIN_RECOUP_REFRESH. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Hash of the (revoked) denomination public key of the coin. + */ + struct TALER_DenominationHashP h_denom_pub; + + /** + * Blinding factor that was used to withdraw the coin. + */ + union TALER_DenominationBlindingKeyP coin_blind; + +}; + + enum GNUNET_GenericReturnValue TALER_wallet_recoup_verify ( const struct TALER_DenominationHashP *h_denom_pub, @@ -243,6 +391,58 @@ TALER_wallet_recoup_refresh_sign ( } +/** + * @brief Message signed by a coin to indicate that the coin should be + * melted. + */ +struct TALER_RefreshMeltCoinAffirmationPS +{ + /** + * Purpose is #TALER_SIGNATURE_WALLET_COIN_MELT. + * Used for an EdDSA signature with the `struct TALER_CoinSpendPublicKeyP`. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Which melt commitment is made by the wallet. + */ + struct TALER_RefreshCommitmentP rc GNUNET_PACKED; + + /** + * Hash over the denomination public key used to sign the coin. + */ + struct TALER_DenominationHashP h_denom_pub GNUNET_PACKED; + + /** + * If age commitment was provided during the withdrawal of the coin, this is + * the hash of the age commitment vector. It must be all zeroes if no age + * commitment was provided. + */ + struct TALER_AgeCommitmentHash h_age_commitment GNUNET_PACKED; + + /** + * 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. We include the + * fee in what is being signed so that we can verify a reserve's + * remaining total balance without needing to access the respective + * denomination key information each time. + */ + struct TALER_AmountNBO amount_with_fee; + + /** + * Melting fee charged by the exchange. This must match the Exchange's + * denomination key's melting fee. If the client puts in an invalid + * melting fee (too high or too low) that does not match the Exchange's + * denomination key, the melting operation is invalid and will be + * rejected by the exchange. The @e amount_with_fee minus the @e + * melt_fee is the amount that will be credited to the melting + * session. + */ + struct TALER_AmountNBO melt_fee; +}; + + void TALER_wallet_melt_sign ( const struct TALER_Amount *amount_with_fee, @@ -308,6 +508,40 @@ TALER_wallet_melt_verify ( } +/** + * @brief Format used for to generate the signature on a request to withdraw + * coins from a reserve. + */ +struct TALER_WithdrawRequestPS +{ + + /** + * Purpose must be #TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW. + * Used with an EdDSA signature of a `struct TALER_ReservePublicKeyP`. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Value of the coin being exchanged (matching the denomination key) + * plus the transaction fee. We include this in what is being + * signed so that we can verify a reserve's remaining total balance + * without needing to access the respective denomination key + * information each time. + */ + struct TALER_AmountNBO amount_with_fee; + + /** + * Hash of the denomination public key for the coin that is withdrawn. + */ + struct TALER_DenominationHashP h_denomination_pub GNUNET_PACKED; + + /** + * Hash of the (blinded) message to be signed by the Exchange. + */ + struct TALER_BlindedCoinHashP h_coin_envelope GNUNET_PACKED; +}; + + void TALER_wallet_withdraw_sign ( const struct TALER_DenominationHashP *h_denom_pub, @@ -373,6 +607,50 @@ TALER_wallet_account_setup_sign ( } +enum GNUNET_GenericReturnValue +TALER_wallet_account_setup_verify ( + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_ReserveSignatureP *reserve_sig) +{ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose = { + .size = htonl (sizeof (purpose)), + .purpose = htonl (TALER_SIGNATURE_WALLET_ACCOUNT_SETUP) + }; + + return GNUNET_CRYPTO_eddsa_verify_ ( + TALER_SIGNATURE_WALLET_RESERVE_STATUS, + &purpose, + &reserve_sig->eddsa_signature, + &reserve_pub->eddsa_pub); +} + + +/** + * Response by which a wallet requests a full + * reserve history and indicates it is willing + * to pay for it. + */ +struct TALER_ReserveHistoryRequestPS +{ + + /** + * Purpose is #TALER_SIGNATURE_WALLET_RESERVE_HISTORY + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * When did the wallet make the requst. + */ + struct GNUNET_TIME_TimestampNBO request_timestamp; + + /** + * How much does the exchange charge for the history? + */ + struct TALER_AmountNBO history_fee; + +}; + + enum GNUNET_GenericReturnValue TALER_wallet_reserve_history_verify ( const struct GNUNET_TIME_Timestamp ts, @@ -417,6 +695,25 @@ TALER_wallet_reserve_history_sign ( } +/** + * Response by which a wallet requests an account status. + */ +struct TALER_ReserveStatusRequestPS +{ + + /** + * Purpose is #TALER_SIGNATURE_WALLET_RESERVE_STATUS + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * When did the wallet make the requst. + */ + struct GNUNET_TIME_TimestampNBO request_timestamp; + +}; + + enum GNUNET_GenericReturnValue TALER_wallet_reserve_status_verify ( const struct GNUNET_TIME_Timestamp ts, @@ -455,4 +752,410 @@ TALER_wallet_reserve_status_sign ( } +/** + * Message signed to create a purse (without reserve). + */ +struct TALER_PurseCreatePS +{ + + /** + * Purpose is #TALER_SIGNATURE_WALLET_PURSE_CREATE + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Time when the purse will expire if still unmerged or unpaid. + */ + struct GNUNET_TIME_TimestampNBO purse_expiration; + + /** + * Total amount (with fees) to be put into the purse. + */ + struct TALER_AmountNBO purse_amount; + + /** + * Contract this purse pays for. + */ + struct TALER_PrivateContractHashP h_contract_terms; + + /** + * Minimum age required for payments into this purse. + */ + uint32_t min_age GNUNET_PACKED; + +}; + + +void +TALER_wallet_purse_create_sign ( + struct GNUNET_TIME_Timestamp purse_expiration, + struct TALER_PrivateContractHashP *h_contract_terms, + uint32_t min_age, + const struct TALER_Amount *amount, + const struct TALER_PursePrivateKeyP *purse_priv, + struct TALER_PurseSignatureP *purse_sig) +{ + struct TALER_PurseCreatePS pm = { + .purpose.size = htonl (sizeof (pm)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_CREATE), + .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration), + .h_contract_terms = *h_contract_terms, + .min_age = htonl (min_age) + }; + + TALER_amount_hton (&pm.purse_amount, + amount); + GNUNET_CRYPTO_eddsa_sign (&purse_priv->eddsa_priv, + &pm, + &purse_sig->eddsa_signature); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_purse_create_verify ( + struct GNUNET_TIME_Timestamp purse_expiration, + struct TALER_PrivateContractHashP *h_contract_terms, + uint32_t min_age, + const struct TALER_Amount *amount, + const struct TALER_PursePublicKeyP *purse_pub, + const struct TALER_PurseSignatureP *purse_sig) +{ + struct TALER_PurseCreatePS pm = { + .purpose.size = htonl (sizeof (pm)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_CREATE), + .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration), + .h_contract_terms = *h_contract_terms, + .min_age = htonl (min_age) + }; + + TALER_amount_hton (&pm.purse_amount, + amount); + return GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_WALLET_PURSE_CREATE, + &pm, + &purse_sig->eddsa_signature, + &purse_pub->eddsa_pub); +} + + +void +TALER_wallet_purse_status_sign ( + const struct TALER_PursePrivateKeyP *purse_priv, + struct TALER_PurseSignatureP *purse_sig) +{ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose = { + .size = htonl (sizeof (purpose)), + .purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_STATUS) + }; + + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_sign_ (&purse_priv->eddsa_priv, + &purpose, + &purse_sig->eddsa_signature)); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_purse_status_verify ( + const struct TALER_PursePublicKeyP *purse_pub, + const struct TALER_PurseSignatureP *purse_sig) +{ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose = { + .size = htonl (sizeof (purpose)), + .purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_STATUS) + }; + + return GNUNET_CRYPTO_eddsa_verify_ (TALER_SIGNATURE_WALLET_PURSE_STATUS, + &purpose, + &purse_sig->eddsa_signature, + &purse_pub->eddsa_pub); +} + + +/** + * Message signed to deposit a coin into a purse. + */ +struct TALER_PurseDepositPS +{ + + /** + * Purpose is #TALER_SIGNATURE_WALLET_PURSE_DEPOSIT + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Amount (with deposit fee) to be deposited into the purse. + */ + struct TALER_AmountNBO coin_amount; + + /** + * Purse to deposit funds into. + */ + struct TALER_PursePublicKeyP purse_pub; + +}; + + +void +TALER_wallet_purse_deposit_sign ( + const struct TALER_PursePublicKeyP *purse_pub, + const struct TALER_Amount *amount, + const struct TALER_CoinSpendPrivateKeyP *coin_priv, + struct TALER_CoinSpendSignatureP *coin_sig) +{ + struct TALER_PurseDepositPS pm = { + .purpose.size = htonl (sizeof (pm)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_DEPOSIT), + .purse_pub = *purse_pub, + }; + + TALER_amount_hton (&pm.coin_amount, + amount); + GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv, + &pm, + &coin_sig->eddsa_signature); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_purse_deposit_verify ( + const struct TALER_PursePublicKeyP *purse_pub, + const struct TALER_Amount *amount, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_CoinSpendSignatureP *coin_sig) +{ + struct TALER_PurseDepositPS pm = { + .purpose.size = htonl (sizeof (pm)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_DEPOSIT), + .purse_pub = *purse_pub, + }; + + TALER_amount_hton (&pm.coin_amount, + amount); + return GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_WALLET_PURSE_DEPOSIT, + &pm, + &coin_sig->eddsa_signature, + &coin_pub->eddsa_pub); +} + + +/** + * Message signed to merge a purse into a reserve. + */ +struct TALER_PurseMergePS +{ + + /** + * Purpose is #TALER_SIGNATURE_WALLET_PURSE_MERGE + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Time when the purse is merged into the reserve. + */ + struct GNUNET_TIME_TimestampNBO merge_timestamp; + + /** + * Which reserve should the purse be merged with. + * Hash of the reserve's payto:// URI. + */ + struct TALER_PaytoHashP h_payto; + +}; + + +void +TALER_wallet_purse_merge_sign ( + const char *reserve_url, + struct GNUNET_TIME_Timestamp merge_timestamp, + const struct TALER_PursePrivateKeyP *purse_priv, + struct TALER_PurseSignatureP *purse_sig) +{ + struct TALER_PurseMergePS pm = { + .purpose.size = htonl (sizeof (pm)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_MERGE), + .merge_timestamp = GNUNET_TIME_timestamp_hton (merge_timestamp), + }; + + TALER_payto_hash (reserve_url, + &pm.h_payto); + GNUNET_CRYPTO_eddsa_sign (&purse_priv->eddsa_priv, + &pm, + &purse_sig->eddsa_signature); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_purse_merge_verify ( + const char *reserve_url, + struct GNUNET_TIME_Timestamp merge_timestamp, + const struct TALER_PursePublicKeyP *purse_pub, + const struct TALER_PurseSignatureP *purse_sig) +{ + struct TALER_PurseMergePS pm = { + .purpose.size = htonl (sizeof (pm)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_PURSE_MERGE), + .merge_timestamp = GNUNET_TIME_timestamp_hton (merge_timestamp), + }; + + TALER_payto_hash (reserve_url, + &pm.h_payto); + return GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_WALLET_ACCOUNT_MERGE, + &pm, + &purse_sig->eddsa_signature, + &purse_pub->eddsa_pub); +} + + +/** + * Message signed by account to merge a purse into a reserve. + */ +struct TALER_AccountMergePS +{ + + /** + * Purpose is #TALER_SIGNATURE_WALLET_ACCOUNT_MERGE + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Time when the purse will expire if still unmerged or unpaid. + */ + struct GNUNET_TIME_TimestampNBO purse_expiration; + + /** + * Total amount (with fees) to be put into the purse. + */ + struct TALER_AmountNBO purse_amount; + + /** + * Which reserve should the purse be merged with. + * Hash of the reserve's payto:// URI. + */ + struct TALER_PaytoHashP h_payto; + + /** + * Contract this purse pays for. + */ + struct TALER_PrivateContractHashP h_contract_terms; + + /** + * Purse to merge. + */ + struct TALER_PursePublicKeyP purse_pub; + + /** + * Time when the purse is merged into the reserve. + */ + struct GNUNET_TIME_TimestampNBO merge_timestamp; + + /** + * Minimum age required for payments into this purse. + */ + uint32_t min_age GNUNET_PACKED; +}; + + +void +TALER_wallet_account_merge_sign ( + const char *reserve_url, + struct GNUNET_TIME_Timestamp merge_timestamp, + const struct TALER_PursePublicKeyP *purse_pub, + struct GNUNET_TIME_Timestamp purse_expiration, + struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_Amount *amount, + uint32_t min_age, + const struct TALER_ReservePrivateKeyP *reserve_priv, + struct TALER_ReserveSignatureP *reserve_sig) +{ + struct TALER_AccountMergePS pm = { + .purpose.size = htonl (sizeof (pm)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_ACCOUNT_MERGE), + .merge_timestamp = GNUNET_TIME_timestamp_hton (merge_timestamp), + .purse_pub = *purse_pub, + .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration), + .h_contract_terms = *h_contract_terms, + .min_age = htonl (min_age) + }; + + TALER_amount_hton (&pm.purse_amount, + amount); + TALER_payto_hash (reserve_url, + &pm.h_payto); + GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv, + &pm, + &reserve_sig->eddsa_signature); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_account_merge_verify ( + const char *reserve_url, + struct GNUNET_TIME_Timestamp merge_timestamp, + const struct TALER_PursePublicKeyP *purse_pub, + struct GNUNET_TIME_Timestamp purse_expiration, + struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_Amount *amount, + uint32_t min_age, + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_ReserveSignatureP *reserve_sig) +{ + struct TALER_AccountMergePS pm = { + .purpose.size = htonl (sizeof (pm)), + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_ACCOUNT_MERGE), + .merge_timestamp = GNUNET_TIME_timestamp_hton (merge_timestamp), + .purse_pub = *purse_pub, + .purse_expiration = GNUNET_TIME_timestamp_hton (purse_expiration), + .h_contract_terms = *h_contract_terms, + .min_age = htonl (min_age) + }; + + TALER_amount_hton (&pm.purse_amount, + amount); + TALER_payto_hash (reserve_url, + &pm.h_payto); + return GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_WALLET_ACCOUNT_MERGE, + &pm, + &reserve_sig->eddsa_signature, + &reserve_pub->eddsa_pub); +} + + +void +TALER_wallet_account_close_sign ( + const struct TALER_ReservePrivateKeyP *reserve_priv, + struct TALER_ReserveSignatureP *reserve_sig) +{ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose = { + .size = htonl (sizeof (purpose)), + .purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_CLOSE) + }; + + GNUNET_assert (GNUNET_OK == + GNUNET_CRYPTO_eddsa_sign_ (&reserve_priv->eddsa_priv, + &purpose, + &reserve_sig->eddsa_signature)); +} + + +enum GNUNET_GenericReturnValue +TALER_wallet_account_close_verify ( + const struct TALER_ReservePublicKeyP *reserve_pub, + const struct TALER_ReserveSignatureP *reserve_sig) +{ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose = { + .size = htonl (sizeof (purpose)), + .purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_CLOSE) + }; + + return GNUNET_CRYPTO_eddsa_verify_ (TALER_SIGNATURE_WALLET_RESERVE_CLOSE, + &purpose, + &reserve_sig->eddsa_signature, + &reserve_pub->eddsa_pub); +} + + /* end of wallet_signatures.c */ -- cgit v1.2.3