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

Generated by: LCOV version 2.0-1