LCOV - code coverage report
Current view: top level - util - merchant_signatures.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 82.0 % 61 50
Test Date: 2026-01-04 22:17:00 Functions: 80.0 % 10 8

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2020, 2024 Taler Systems SA
       4              : 
       5              :   TALER is free software; you can redistribute it and/or modify it under the
       6              :   terms of the GNU General Public License as published by the Free Software
       7              :   Foundation; either version 3, or (at your option) any later version.
       8              : 
       9              :   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
      10              :   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
      11              :   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
      12              : 
      13              :   You should have received a copy of the GNU General Public License along with
      14              :   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
      15              : */
      16              : /**
      17              :  * @file merchant_signatures.c
      18              :  * @brief Utility functions for Taler merchant signatures
      19              :  * @author Christian Grothoff
      20              :  */
      21              : #include "taler/platform.h"
      22              : #include "taler/taler_util.h"
      23              : #include "taler/taler_signatures.h"
      24              : 
      25              : 
      26              : GNUNET_NETWORK_STRUCT_BEGIN
      27              : 
      28              : /**
      29              :  * @brief Format used to generate the signature on a request to obtain
      30              :  * the wire transfer identifier associated with a deposit.
      31              :  */
      32              : struct TALER_DepositTrackPS
      33              : {
      34              :   /**
      35              :    * Purpose must be #TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION.
      36              :    */
      37              :   struct GNUNET_CRYPTO_SignaturePurpose purpose;
      38              : 
      39              :   /**
      40              :    * Hash over the proposal data of the contract for which this deposit is made.
      41              :    */
      42              :   struct TALER_PrivateContractHashP h_contract_terms GNUNET_PACKED;
      43              : 
      44              :   /**
      45              :    * Hash over the wiring information of the merchant.
      46              :    */
      47              :   struct TALER_MerchantWireHashP h_wire GNUNET_PACKED;
      48              : 
      49              :   /**
      50              :    * The coin's public key.  This is the value that must have been
      51              :    * signed (blindly) by the Exchange.
      52              :    */
      53              :   struct TALER_CoinSpendPublicKeyP coin_pub;
      54              : 
      55              : };
      56              : 
      57              : GNUNET_NETWORK_STRUCT_END
      58              : 
      59              : 
      60              : void
      61            8 : TALER_merchant_deposit_sign (
      62              :   const struct TALER_PrivateContractHashP *h_contract_terms,
      63              :   const struct TALER_MerchantWireHashP *h_wire,
      64              :   const struct TALER_CoinSpendPublicKeyP *coin_pub,
      65              :   const struct TALER_MerchantPrivateKeyP *merchant_priv,
      66              :   struct TALER_MerchantSignatureP *merchant_sig)
      67              : {
      68            8 :   struct TALER_DepositTrackPS dtp = {
      69            8 :     .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION),
      70            8 :     .purpose.size = htonl (sizeof (dtp)),
      71              :     .h_contract_terms = *h_contract_terms,
      72              :     .h_wire = *h_wire,
      73              :     .coin_pub = *coin_pub
      74              :   };
      75              : 
      76            8 :   GNUNET_CRYPTO_eddsa_sign (&merchant_priv->eddsa_priv,
      77              :                             &dtp,
      78              :                             &merchant_sig->eddsa_sig);
      79            8 : }
      80              : 
      81              : 
      82              : enum GNUNET_GenericReturnValue
      83            8 : TALER_merchant_deposit_verify (
      84              :   const struct TALER_MerchantPublicKeyP *merchant,
      85              :   const struct TALER_CoinSpendPublicKeyP *coin_pub,
      86              :   const struct TALER_PrivateContractHashP *h_contract_terms,
      87              :   const struct TALER_MerchantWireHashP *h_wire,
      88              :   const struct TALER_MerchantSignatureP *merchant_sig)
      89              : {
      90            8 :   struct TALER_DepositTrackPS tps = {
      91            8 :     .purpose.size = htonl (sizeof (tps)),
      92            8 :     .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION),
      93              :     .coin_pub = *coin_pub,
      94              :     .h_contract_terms = *h_contract_terms,
      95              :     .h_wire = *h_wire
      96              :   };
      97              : 
      98            8 :   return GNUNET_CRYPTO_eddsa_verify (
      99              :     TALER_SIGNATURE_MERCHANT_TRACK_TRANSACTION,
     100              :     &tps,
     101              :     &merchant_sig->eddsa_sig,
     102              :     &merchant->eddsa_pub);
     103              : }
     104              : 
     105              : 
     106              : /**
     107              :  * @brief Format used to generate the signature on a request to refund
     108              :  * a coin into the account of the customer.
     109              :  */
     110              : struct TALER_RefundRequestPS
     111              : {
     112              :   /**
     113              :    * Purpose must be #TALER_SIGNATURE_MERCHANT_REFUND.
     114              :    */
     115              :   struct GNUNET_CRYPTO_SignaturePurpose purpose;
     116              : 
     117              :   /**
     118              :    * Hash over the proposal data to identify the contract
     119              :    * which is being refunded.
     120              :    */
     121              :   struct TALER_PrivateContractHashP h_contract_terms GNUNET_PACKED;
     122              : 
     123              :   /**
     124              :    * The coin's public key.  This is the value that must have been
     125              :    * signed (blindly) by the Exchange.
     126              :    */
     127              :   struct TALER_CoinSpendPublicKeyP coin_pub;
     128              : 
     129              :   /**
     130              :    * Merchant-generated transaction ID for the refund.
     131              :    */
     132              :   uint64_t rtransaction_id GNUNET_PACKED;
     133              : 
     134              :   /**
     135              :    * Amount to be refunded, including refund fee charged by the
     136              :    * exchange to the customer.
     137              :    */
     138              :   struct TALER_AmountNBO refund_amount;
     139              : };
     140              : 
     141              : 
     142              : void
     143           28 : TALER_merchant_refund_sign (
     144              :   const struct TALER_CoinSpendPublicKeyP *coin_pub,
     145              :   const struct TALER_PrivateContractHashP *h_contract_terms,
     146              :   uint64_t rtransaction_id,
     147              :   const struct TALER_Amount *amount,
     148              :   const struct TALER_MerchantPrivateKeyP *merchant_priv,
     149              :   struct TALER_MerchantSignatureP *merchant_sig)
     150              : {
     151           56 :   struct TALER_RefundRequestPS rr = {
     152           28 :     .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND),
     153           28 :     .purpose.size = htonl (sizeof (rr)),
     154              :     .h_contract_terms = *h_contract_terms,
     155              :     .coin_pub = *coin_pub,
     156           28 :     .rtransaction_id = GNUNET_htonll (rtransaction_id)
     157              :   };
     158              : 
     159           28 :   TALER_amount_hton (&rr.refund_amount,
     160              :                      amount);
     161           28 :   GNUNET_CRYPTO_eddsa_sign (&merchant_priv->eddsa_priv,
     162              :                             &rr,
     163              :                             &merchant_sig->eddsa_sig);
     164           28 : }
     165              : 
     166              : 
     167              : enum GNUNET_GenericReturnValue
     168           14 : TALER_merchant_refund_verify (
     169              :   const struct TALER_CoinSpendPublicKeyP *coin_pub,
     170              :   const struct TALER_PrivateContractHashP *h_contract_terms,
     171              :   uint64_t rtransaction_id,
     172              :   const struct TALER_Amount *amount,
     173              :   const struct TALER_MerchantPublicKeyP *merchant_pub,
     174              :   const struct TALER_MerchantSignatureP *merchant_sig)
     175              : {
     176           28 :   struct TALER_RefundRequestPS rr = {
     177           14 :     .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_REFUND),
     178           14 :     .purpose.size = htonl (sizeof (rr)),
     179              :     .h_contract_terms = *h_contract_terms,
     180              :     .coin_pub = *coin_pub,
     181           14 :     .rtransaction_id = GNUNET_htonll (rtransaction_id)
     182              :   };
     183              : 
     184           14 :   TALER_amount_hton (&rr.refund_amount,
     185              :                      amount);
     186           14 :   return GNUNET_CRYPTO_eddsa_verify (
     187              :     TALER_SIGNATURE_MERCHANT_REFUND,
     188              :     &rr,
     189              :     &merchant_sig->eddsa_sig,
     190              :     &merchant_pub->eddsa_pub);
     191              : }
     192              : 
     193              : 
     194              : /**
     195              :  * @brief Information signed by the exchange's master
     196              :  * key affirming the IBAN details for the exchange.
     197              :  */
     198              : struct TALER_MerchantWireDetailsPS
     199              : {
     200              : 
     201              :   /**
     202              :    * Purpose is #TALER_SIGNATURE_MERCHANT_WIRE_DETAILS.
     203              :    */
     204              :   struct GNUNET_CRYPTO_SignaturePurpose purpose;
     205              : 
     206              :   /**
     207              :    * Salted hash over the account holder's payto:// URL and
     208              :    * the salt, as done by #TALER_merchant_wire_signature_hash().
     209              :    */
     210              :   struct TALER_MerchantWireHashP h_wire_details GNUNET_PACKED;
     211              : 
     212              : };
     213              : 
     214              : 
     215              : enum GNUNET_GenericReturnValue
     216            3 : TALER_merchant_wire_signature_check (
     217              :   const struct TALER_FullPayto payto_uri,
     218              :   const struct TALER_WireSaltP *salt,
     219              :   const struct TALER_MerchantPublicKeyP *merch_pub,
     220              :   const struct TALER_MerchantSignatureP *merch_sig)
     221              : {
     222            3 :   struct TALER_MerchantWireDetailsPS wd = {
     223            3 :     .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_WIRE_DETAILS),
     224            3 :     .purpose.size = htonl (sizeof (wd))
     225              :   };
     226              : 
     227            3 :   TALER_merchant_wire_signature_hash (payto_uri,
     228              :                                       salt,
     229              :                                       &wd.h_wire_details);
     230            3 :   return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MERCHANT_WIRE_DETAILS,
     231              :                                      &wd,
     232              :                                      &merch_sig->eddsa_sig,
     233              :                                      &merch_pub->eddsa_pub);
     234              : }
     235              : 
     236              : 
     237              : void
     238            1 : TALER_merchant_wire_signature_make (
     239              :   const struct TALER_FullPayto payto_uri,
     240              :   const struct TALER_WireSaltP *salt,
     241              :   const struct TALER_MerchantPrivateKeyP *merch_priv,
     242              :   struct TALER_MerchantSignatureP *merch_sig)
     243              : {
     244            1 :   struct TALER_MerchantWireDetailsPS wd = {
     245            1 :     .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_WIRE_DETAILS),
     246            1 :     .purpose.size = htonl (sizeof (wd))
     247              :   };
     248              : 
     249            1 :   TALER_merchant_wire_signature_hash (payto_uri,
     250              :                                       salt,
     251              :                                       &wd.h_wire_details);
     252            1 :   GNUNET_CRYPTO_eddsa_sign (&merch_priv->eddsa_priv,
     253              :                             &wd,
     254              :                             &merch_sig->eddsa_sig);
     255            1 : }
     256              : 
     257              : 
     258              : /**
     259              :  * Used by merchants to return signed responses to /pay requests.
     260              :  * Currently only used to return 200 OK signed responses.
     261              :  */
     262              : struct TALER_PaymentResponsePS
     263              : {
     264              :   /**
     265              :    * Set to #TALER_SIGNATURE_MERCHANT_PAYMENT_OK. Note that
     266              :    * unsuccessful payments are usually proven by some exchange's signature.
     267              :    */
     268              :   struct GNUNET_CRYPTO_SignaturePurpose purpose;
     269              : 
     270              :   /**
     271              :    * Hash of the proposal data associated with this confirmation
     272              :    */
     273              :   struct TALER_PrivateContractHashP h_contract_terms;
     274              : };
     275              : 
     276              : void
     277            0 : TALER_merchant_pay_sign (
     278              :   const struct TALER_PrivateContractHashP *h_contract_terms,
     279              :   const struct TALER_MerchantPrivateKeyP *merch_priv,
     280              :   struct TALER_MerchantSignatureP *merch_sig)
     281              : {
     282            0 :   struct TALER_PaymentResponsePS mr = {
     283            0 :     .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_PAYMENT_OK),
     284            0 :     .purpose.size = htonl (sizeof (mr)),
     285              :     .h_contract_terms = *h_contract_terms
     286              :   };
     287              : 
     288            0 :   GNUNET_CRYPTO_eddsa_sign (&merch_priv->eddsa_priv,
     289              :                             &mr,
     290              :                             &merch_sig->eddsa_sig);
     291            0 : }
     292              : 
     293              : 
     294              : enum GNUNET_GenericReturnValue
     295            0 : TALER_merchant_pay_verify (
     296              :   const struct TALER_PrivateContractHashP *h_contract_terms,
     297              :   const struct TALER_MerchantPublicKeyP *merchant_pub,
     298              :   const struct TALER_MerchantSignatureP *merchant_sig)
     299              : {
     300            0 :   struct TALER_PaymentResponsePS pr = {
     301            0 :     .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_PAYMENT_OK),
     302            0 :     .purpose.size = htonl (sizeof (pr)),
     303              :     .h_contract_terms = *h_contract_terms
     304              :   };
     305              : 
     306            0 :   return GNUNET_CRYPTO_eddsa_verify (
     307              :     TALER_SIGNATURE_MERCHANT_PAYMENT_OK,
     308              :     &pr,
     309              :     &merchant_sig->eddsa_sig,
     310              :     &merchant_pub->eddsa_pub);
     311              : }
     312              : 
     313              : 
     314              : /**
     315              :  * The contract sent by the merchant to the wallet.
     316              :  */
     317              : struct TALER_ProposalDataPS
     318              : {
     319              :   /**
     320              :    * Purpose header for the signature over the proposal data
     321              :    * with purpose #TALER_SIGNATURE_MERCHANT_CONTRACT.
     322              :    */
     323              :   struct GNUNET_CRYPTO_SignaturePurpose purpose;
     324              : 
     325              :   /**
     326              :    * Hash of the JSON contract in UTF-8 including 0-termination,
     327              :    * using JSON_COMPACT | JSON_SORT_KEYS
     328              :    */
     329              :   struct TALER_PrivateContractHashP hash;
     330              : };
     331              : 
     332              : 
     333              : void
     334           98 : TALER_merchant_contract_sign (
     335              :   const struct TALER_PrivateContractHashP *h_contract_terms,
     336              :   const struct TALER_MerchantPrivateKeyP *merchant_priv,
     337              :   struct TALER_MerchantSignatureP *merchant_sig)
     338              : {
     339           98 :   struct TALER_ProposalDataPS pdps = {
     340           98 :     .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT),
     341           98 :     .purpose.size = htonl (sizeof (pdps)),
     342              :     .hash = *h_contract_terms
     343              :   };
     344              : 
     345           98 :   GNUNET_CRYPTO_eddsa_sign (&merchant_priv->eddsa_priv,
     346              :                             &pdps,
     347              :                             &merchant_sig->eddsa_sig);
     348           98 : }
     349              : 
     350              : 
     351              : enum GNUNET_GenericReturnValue
     352           98 : TALER_merchant_contract_verify (
     353              :   const struct TALER_PrivateContractHashP *h_contract_terms,
     354              :   const struct TALER_MerchantPublicKeyP *merchant_pub,
     355              :   struct TALER_MerchantSignatureP *merchant_sig)
     356              : {
     357           98 :   struct TALER_ProposalDataPS pdps = {
     358           98 :     .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_CONTRACT),
     359           98 :     .purpose.size = htonl (sizeof (pdps)),
     360              :     .hash = *h_contract_terms
     361              :   };
     362              : 
     363           98 :   return GNUNET_CRYPTO_eddsa_verify (
     364              :     TALER_SIGNATURE_MERCHANT_CONTRACT,
     365              :     &pdps,
     366              :     &merchant_sig->eddsa_sig,
     367              :     &merchant_pub->eddsa_pub);
     368              : }
     369              : 
     370              : 
     371              : /* end of merchant_signatures.c */
        

Generated by: LCOV version 2.0-1