diff options
Diffstat (limited to 'src/util/merchant_signatures.c')
-rw-r--r-- | src/util/merchant_signatures.c | 352 |
1 files changed, 352 insertions, 0 deletions
diff --git a/src/util/merchant_signatures.c b/src/util/merchant_signatures.c new file mode 100644 index 000000000..35e0b0e07 --- /dev/null +++ b/src/util/merchant_signatures.c @@ -0,0 +1,352 @@ +/* + This file is part of TALER + Copyright (C) 2020 Taler Systems SA + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file merchant_signatures.c + * @brief Utility functions for Taler merchant signatures + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_util.h" +#include "taler_signatures.h" + + +GNUNET_NETWORK_STRUCT_BEGIN + +/** + * @brief Format used to generate the signature on a request to obtain + * the wire transfer identifier associated with a deposit. + */ +struct TALER_DepositTrackPS +{ + /** + * Purpose must be #TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Hash over the proposal data of the contract for which this deposit is made. + */ + struct TALER_PrivateContractHashP h_contract_terms GNUNET_PACKED; + + /** + * Hash over the wiring information of the merchant. + */ + struct TALER_MerchantWireHashP h_wire GNUNET_PACKED; + + /** + * The coin's public key. This is the value that must have been + * signed (blindly) by the Exchange. + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + +}; + +GNUNET_NETWORK_STRUCT_END + + +void +TALER_merchant_deposit_sign ( + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_MerchantWireHashP *h_wire, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_MerchantPrivateKeyP *merchant_priv, + struct TALER_MerchantSignatureP *merchant_sig) +{ + struct TALER_DepositTrackPS dtp = { + .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION), + .purpose.size = htonl (sizeof (dtp)), + .h_contract_terms = *h_contract_terms, + .h_wire = *h_wire, + .coin_pub = *coin_pub + }; + + GNUNET_CRYPTO_eddsa_sign (&merchant_priv->eddsa_priv, + &dtp, + &merchant_sig->eddsa_sig); +} + + +enum GNUNET_GenericReturnValue +TALER_merchant_deposit_verify ( + const struct TALER_MerchantPublicKeyP *merchant, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_MerchantWireHashP *h_wire, + const struct TALER_MerchantSignatureP *merchant_sig) +{ + struct TALER_DepositTrackPS tps = { + .purpose.size = htonl (sizeof (tps)), + .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION), + .coin_pub = *coin_pub, + .h_contract_terms = *h_contract_terms, + .h_wire = *h_wire + }; + + return + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION, + &tps, + &merchant_sig->eddsa_sig, + &merchant->eddsa_pub); +} + + +/** + * @brief Format used to generate the signature on a request to refund + * a coin into the account of the customer. + */ +struct TALER_RefundRequestPS +{ + /** + * Purpose must be #TALER_SIGNATURE_MERCHANT_REFUND. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Hash over the proposal data to identify the contract + * which is being refunded. + */ + struct TALER_PrivateContractHashP h_contract_terms GNUNET_PACKED; + + /** + * The coin's public key. This is the value that must have been + * signed (blindly) by the Exchange. + */ + struct TALER_CoinSpendPublicKeyP coin_pub; + + /** + * Merchant-generated transaction ID for the refund. + */ + uint64_t rtransaction_id GNUNET_PACKED; + + /** + * Amount to be refunded, including refund fee charged by the + * exchange to the customer. + */ + struct TALER_AmountNBO refund_amount; +}; + + +void +TALER_merchant_refund_sign ( + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_PrivateContractHashP *h_contract_terms, + uint64_t rtransaction_id, + const struct TALER_Amount *amount, + const struct TALER_MerchantPrivateKeyP *merchant_priv, + struct TALER_MerchantSignatureP *merchant_sig) +{ + struct TALER_RefundRequestPS rr = { + .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND), + .purpose.size = htonl (sizeof (rr)), + .h_contract_terms = *h_contract_terms, + .coin_pub = *coin_pub, + .rtransaction_id = GNUNET_htonll (rtransaction_id) + }; + + TALER_amount_hton (&rr.refund_amount, + amount); + GNUNET_CRYPTO_eddsa_sign (&merchant_priv->eddsa_priv, + &rr, + &merchant_sig->eddsa_sig); +} + + +enum GNUNET_GenericReturnValue +TALER_merchant_refund_verify ( + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_PrivateContractHashP *h_contract_terms, + uint64_t rtransaction_id, + const struct TALER_Amount *amount, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct TALER_MerchantSignatureP *merchant_sig) +{ + struct TALER_RefundRequestPS rr = { + .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND), + .purpose.size = htonl (sizeof (rr)), + .h_contract_terms = *h_contract_terms, + .coin_pub = *coin_pub, + .rtransaction_id = GNUNET_htonll (rtransaction_id) + }; + + TALER_amount_hton (&rr.refund_amount, + amount); + return + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_REFUND, + &rr, + &merchant_sig->eddsa_sig, + &merchant_pub->eddsa_pub); +} + + +/** + * @brief Information signed by the exchange's master + * key affirming the IBAN details for the exchange. + */ +struct TALER_MerchantWireDetailsPS +{ + + /** + * Purpose is #TALER_SIGNATURE_MERCHANT_WIRE_DETAILS. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Salted hash over the account holder's payto:// URL and + * the salt, as done by #TALER_merchant_wire_signature_hash(). + */ + struct TALER_MerchantWireHashP h_wire_details GNUNET_PACKED; + +}; + + +enum GNUNET_GenericReturnValue +TALER_merchant_wire_signature_check ( + const char *payto_uri, + const struct TALER_WireSaltP *salt, + const struct TALER_MerchantPublicKeyP *merch_pub, + const struct TALER_MerchantSignatureP *merch_sig) +{ + struct TALER_MerchantWireDetailsPS wd = { + .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_WIRE_DETAILS), + .purpose.size = htonl (sizeof (wd)) + }; + + TALER_merchant_wire_signature_hash (payto_uri, + salt, + &wd.h_wire_details); + return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_WIRE_DETAILS, + &wd, + &merch_sig->eddsa_sig, + &merch_pub->eddsa_pub); +} + + +void +TALER_merchant_wire_signature_make ( + const char *payto_uri, + const struct TALER_WireSaltP *salt, + const struct TALER_MerchantPrivateKeyP *merch_priv, + struct TALER_MerchantSignatureP *merch_sig) +{ + struct TALER_MerchantWireDetailsPS wd = { + .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_WIRE_DETAILS), + .purpose.size = htonl (sizeof (wd)) + }; + + TALER_merchant_wire_signature_hash (payto_uri, + salt, + &wd.h_wire_details); + GNUNET_CRYPTO_eddsa_sign (&merch_priv->eddsa_priv, + &wd, + &merch_sig->eddsa_sig); +} + + +/** + * Used by merchants to return signed responses to /pay requests. + * Currently only used to return 200 OK signed responses. + */ +struct TALER_PaymentResponsePS +{ + /** + * Set to #TALER_SIGNATURE_MERCHANT_PAYMENT_OK. Note that + * unsuccessful payments are usually proven by some exchange's signature. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Hash of the proposal data associated with this confirmation + */ + struct TALER_PrivateContractHashP h_contract_terms; +}; + +void +TALER_merchant_pay_sign ( + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_MerchantPrivateKeyP *merch_priv, + struct TALER_MerchantSignatureP *merch_sig) +{ + struct TALER_PaymentResponsePS mr = { + .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_PAYMENT_OK), + .purpose.size = htonl (sizeof (mr)), + .h_contract_terms = *h_contract_terms + }; + + GNUNET_CRYPTO_eddsa_sign (&merch_priv->eddsa_priv, + &mr, + &merch_sig->eddsa_sig); +} + + +enum GNUNET_GenericReturnValue +TALER_merchant_pay_verify ( + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_MerchantPublicKeyP *merchant_pub, + const struct TALER_MerchantSignatureP *merchant_sig) +{ + struct TALER_PaymentResponsePS pr = { + .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_PAYMENT_OK), + .purpose.size = htonl (sizeof (pr)), + .h_contract_terms = *h_contract_terms + }; + + return + GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_PAYMENT_OK, + &pr, + &merchant_sig->eddsa_sig, + &merchant_pub->eddsa_pub); +} + + +/** + * The contract sent by the merchant to the wallet. + */ +struct TALER_ProposalDataPS +{ + /** + * Purpose header for the signature over the proposal data + * with purpose #TALER_SIGNATURE_MERCHANT_CONTRACT. + */ + struct GNUNET_CRYPTO_EccSignaturePurpose purpose; + + /** + * Hash of the JSON contract in UTF-8 including 0-termination, + * using JSON_COMPACT | JSON_SORT_KEYS + */ + struct TALER_PrivateContractHashP hash; +}; + +void +TALER_merchant_contract_sign ( + const struct TALER_PrivateContractHashP *h_contract_terms, + const struct TALER_MerchantPrivateKeyP *merch_priv, + struct GNUNET_CRYPTO_EddsaSignature *merch_sig) +{ + struct TALER_ProposalDataPS pdps = { + .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT), + .purpose.size = htonl (sizeof (pdps)), + .hash = *h_contract_terms + }; + + GNUNET_CRYPTO_eddsa_sign (&merch_priv->eddsa_priv, + &pdps, + merch_sig); +} + + +// NB: "TALER_merchant_contract_verify" not (yet?) needed / not defined. + +/* end of merchant_signatures.c */ |