LCOV - code coverage report
Current view: top level - util - test_helper_cs.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 78.7 % 423 333
Test Date: 2026-09-11 18:55:36 Functions: 100.0 % 11 11

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   (C) 2020, 2021, 2023 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 util/test_helper_cs.c
      18              :  * @brief Tests for CS crypto helper
      19              :  * @author Christian Grothoff
      20              :  */
      21              : #include "platform.h"
      22              : #include "taler/taler_util.h"
      23              : 
      24              : /**
      25              :  * Configuration has 1 minute duration and 5 minutes lookahead, but
      26              :  * we do not get 'revocations' for expired keys. So this must be
      27              :  * large enough to deal with key rotation during the runtime of
      28              :  * the benchmark.
      29              :  */
      30              : #define MAX_KEYS 1024
      31              : 
      32              : /**
      33              :  * How many random key revocations should we test?
      34              :  */
      35              : #define NUM_REVOKES 3
      36              : 
      37              : /**
      38              :  * How many iterations of the successful signing test should we run?
      39              :  */
      40              : #define NUM_SIGN_TESTS 5
      41              : 
      42              : /**
      43              :  * How many iterations of the successful signing test should we run
      44              :  * during the benchmark phase?
      45              :  */
      46              : #define NUM_SIGN_PERFS 100
      47              : 
      48              : /**
      49              :  * How many parallel clients should we use for the parallel
      50              :  * benchmark? (> 500 may cause problems with the max open FD number limit).
      51              :  */
      52              : #define NUM_CORES 8
      53              : 
      54              : /**
      55              :  * Number of keys currently in #keys.
      56              :  */
      57              : static unsigned int num_keys;
      58              : 
      59              : /**
      60              :  * Keys currently managed by the helper.
      61              :  */
      62              : struct KeyData
      63              : {
      64              :   /**
      65              :    * Validity start point.
      66              :    */
      67              :   struct GNUNET_TIME_Timestamp start_time;
      68              : 
      69              :   /**
      70              :    * Key expires for signing at @e start_time plus this value.
      71              :    */
      72              :   struct GNUNET_TIME_Relative validity_duration;
      73              : 
      74              :   /**
      75              :    * Hash of the public key.
      76              :    */
      77              :   struct TALER_CsPubHashP h_cs;
      78              : 
      79              :   /**
      80              :    * Full public key.
      81              :    */
      82              :   struct TALER_DenominationPublicKey denom_pub;
      83              : 
      84              :   /**
      85              :    * Is this key currently valid?
      86              :    */
      87              :   bool valid;
      88              : 
      89              :   /**
      90              :    * Did the test driver revoke this key?
      91              :    */
      92              :   bool revoked;
      93              : };
      94              : 
      95              : /**
      96              :  * Array of all the keys we got from the helper.
      97              :  */
      98              : static struct KeyData keys[MAX_KEYS];
      99              : 
     100              : 
     101              : /**
     102              :  * Release memory occupied by #keys.
     103              :  */
     104              : static void
     105            9 : free_keys (void)
     106              : {
     107         9225 :   for (unsigned int i = 0; i<MAX_KEYS; i++)
     108         9216 :     if (keys[i].valid)
     109              :     {
     110           69 :       TALER_denom_pub_free (&keys[i].denom_pub);
     111           69 :       keys[i].valid = false;
     112           69 :       GNUNET_assert (num_keys > 0);
     113           69 :       num_keys--;
     114              :     }
     115            9 : }
     116              : 
     117              : 
     118              : /**
     119              :  * Function called with information about available keys for signing.  Usually
     120              :  * only called once per key upon connect. Also called again in case a key is
     121              :  * being revoked, in that case with an @a end_time of zero.  Stores the keys
     122              :  * status in #keys.
     123              :  *
     124              :  * @param cls closure, NULL
     125              :  * @param section_name name of the denomination type in the configuration;
     126              :  *                 NULL if the key has been revoked or purged
     127              :  * @param start_time when does the key become available for signing;
     128              :  *                 zero if the key has been revoked or purged
     129              :  * @param validity_duration how long does the key remain available for signing;
     130              :  *                 zero if the key has been revoked or purged
     131              :  * @param h_cs hash of the @a denom_pub that is available (or was purged)
     132              :  * @param bs_pub the public key itself, NULL if the key was revoked or purged
     133              :  * @param sm_pub public key of the security module, NULL if the key was revoked or purged
     134              :  * @param sm_sig signature from the security module, NULL if the key was revoked or purged
     135              :  *               The signature was already verified against @a sm_pub.
     136              :  */
     137              : static void
     138           75 : key_cb (void *cls,
     139              :         const char *section_name,
     140              :         struct GNUNET_TIME_Timestamp start_time,
     141              :         struct GNUNET_TIME_Relative validity_duration,
     142              :         const struct TALER_CsPubHashP *h_cs,
     143              :         struct GNUNET_CRYPTO_BlindSignPublicKey *bs_pub,
     144              :         const struct TALER_SecurityModulePublicKeyP *sm_pub,
     145              :         const struct TALER_SecurityModuleSignatureP *sm_sig)
     146              : {
     147              :   (void) cls;
     148              :   (void) sm_pub;
     149              :   (void) sm_sig;
     150           75 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     151              :               "Key notification about key %s in `%s'\n",
     152              :               GNUNET_h2s (&h_cs->hash),
     153              :               section_name);
     154           75 :   if (0 == validity_duration.rel_value_us)
     155              :   {
     156            3 :     bool found = false;
     157              : 
     158            3 :     GNUNET_break (NULL == bs_pub);
     159            3 :     GNUNET_break (NULL == section_name);
     160           11 :     for (unsigned int i = 0; i<MAX_KEYS; i++)
     161           11 :       if (0 == GNUNET_memcmp (h_cs,
     162              :                               &keys[i].h_cs))
     163              :       {
     164            3 :         keys[i].valid = false;
     165            3 :         keys[i].revoked = false;
     166            3 :         TALER_denom_pub_free (&keys[i].denom_pub);
     167            3 :         GNUNET_assert (num_keys > 0);
     168            3 :         num_keys--;
     169            3 :         found = true;
     170            3 :         break;
     171              :       }
     172            3 :     if (! found)
     173            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     174              :                   "Error: helper announced expiration of unknown key!\n");
     175              : 
     176            3 :     return;
     177              :   }
     178              : 
     179           72 :   GNUNET_break (NULL != bs_pub);
     180          314 :   for (unsigned int i = 0; i<MAX_KEYS; i++)
     181          314 :     if (! keys[i].valid)
     182              :     {
     183           72 :       keys[i].valid = true;
     184           72 :       keys[i].h_cs = *h_cs;
     185           72 :       keys[i].start_time = start_time;
     186           72 :       keys[i].validity_duration = validity_duration;
     187              :       keys[i].denom_pub.bsign_pub_key
     188           72 :         = GNUNET_CRYPTO_bsign_pub_incref (bs_pub);
     189           72 :       num_keys++;
     190           72 :       return;
     191              :     }
     192              :   /* too many keys! */
     193            0 :   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     194              :               "Error: received %d live keys from the service!\n",
     195              :               MAX_KEYS + 1);
     196              : }
     197              : 
     198              : 
     199              : /**
     200              :  * Test key revocation logic.
     201              :  *
     202              :  * @param dh handle to the helper
     203              :  * @return 0 on success
     204              :  */
     205              : static int
     206            1 : test_revocation (struct TALER_CRYPTO_CsDenominationHelper *dh)
     207              : {
     208            1 :   struct timespec req = {
     209              :     .tv_nsec = 250000000
     210              :   };
     211              : 
     212            4 :   for (unsigned int i = 0; i<NUM_REVOKES; i++)
     213              :   {
     214              :     uint32_t off;
     215              : 
     216            3 :     off = GNUNET_CRYPTO_random_u32 (num_keys);
     217              :     /* find index of key to revoke */
     218           11 :     for (unsigned int j = 0; j < MAX_KEYS; j++)
     219              :     {
     220           11 :       if (! keys[j].valid)
     221            0 :         continue;
     222           11 :       if (0 != off)
     223              :       {
     224            8 :         off--;
     225            8 :         continue;
     226              :       }
     227            3 :       keys[j].revoked = true;
     228            3 :       fprintf (stderr,
     229              :                "Revoking key %s ...",
     230            3 :                GNUNET_h2s (&keys[j].h_cs.hash));
     231            3 :       TALER_CRYPTO_helper_cs_revoke (dh,
     232            3 :                                      &keys[j].h_cs);
     233            6 :       for (unsigned int k = 0; k<1000; k++)
     234              :       {
     235            6 :         TALER_CRYPTO_helper_cs_poll (dh);
     236            6 :         if (! keys[j].revoked)
     237            3 :           break;
     238            3 :         nanosleep (&req, NULL);
     239            3 :         fprintf (stderr, ".");
     240              :       }
     241            3 :       if (keys[j].revoked)
     242              :       {
     243            0 :         fprintf (stderr,
     244              :                  "\nFAILED: timeout trying to revoke key %u\n",
     245              :                  j);
     246            0 :         TALER_CRYPTO_helper_cs_disconnect (dh);
     247            0 :         return 2;
     248              :       }
     249            3 :       fprintf (stderr, "\n");
     250            3 :       break;
     251              :     }
     252              :   }
     253            1 :   return 0;
     254              : }
     255              : 
     256              : 
     257              : /**
     258              :  * Set up planchet secrets and Clause-Schnorr nonces for a withdraw-like
     259              :  * operation.
     260              :  *
     261              :  * @param num number of planchets and nonces to derive
     262              :  * @param for_melt true to use the refresh nonce domain
     263              :  * @param[out] ps planchet secrets to initialize
     264              :  * @param[out] nonces Clause-Schnorr nonces to initialize
     265              :  */
     266              : static void
     267           17 : setup_withdraw_secrets (
     268              :   size_t num,
     269              :   bool for_melt,
     270              :   struct TALER_PlanchetMasterSecretP ps[static num],
     271              :   union GNUNET_CRYPTO_BlindSessionNonce nonces[static num])
     272           17 : {
     273              :   struct TALER_WithdrawMasterSeedP seed;
     274              :   struct TALER_BlindingMasterSeedP blinding_seed;
     275           17 :   uint32_t indices[num];
     276              : 
     277           17 :   TALER_withdraw_master_seed_setup_random (&seed);
     278           17 :   TALER_withdraw_expand_secrets (num,
     279              :                                  &seed,
     280              :                                  ps);
     281           17 :   TALER_cs_withdraw_seed_to_blinding_seed (&seed,
     282              :                                            &blinding_seed);
     283          179 :   for (uint32_t i = 0; i<num; i++)
     284          162 :     indices[i] = i;
     285           17 :   TALER_cs_derive_only_cs_blind_nonces_from_seed (
     286              :     &blinding_seed,
     287              :     for_melt,
     288              :     num,
     289              :     indices,
     290              :     nonces);
     291           17 : }
     292              : 
     293              : 
     294              : /**
     295              :  * Test R derivation logic.
     296              :  *
     297              :  * @param dh handle to the helper
     298              :  * @return 0 on success
     299              :  */
     300              : static int
     301            1 : test_r_derive (struct TALER_CRYPTO_CsDenominationHelper *dh)
     302              : {
     303              :   enum TALER_ErrorCode ec;
     304            1 :   bool success = false;
     305              :   struct TALER_PlanchetMasterSecretP ps;
     306              :   struct TALER_CoinSpendPrivateKeyP coin_priv;
     307              :   union GNUNET_CRYPTO_BlindingSecretP bks;
     308              :   struct TALER_CoinPubHashP c_hash;
     309            1 :   struct GNUNET_CRYPTO_BlindingInputValues bi = {
     310              :     .cipher = GNUNET_CRYPTO_BSA_CS
     311              :   };
     312            1 :   struct TALER_ExchangeBlindingValues alg_values = {
     313              :     .blinding_inputs = &bi
     314              :   };
     315              :   union GNUNET_CRYPTO_BlindSessionNonce nonce;
     316              : 
     317            1 :   setup_withdraw_secrets (1,
     318              :                           false,
     319              :                           &ps,
     320              :                           &nonce);
     321         1025 :   for (unsigned int i = 0; i<MAX_KEYS; i++)
     322              :   {
     323              :     struct TALER_PlanchetDetail pd;
     324              : 
     325         1024 :     if (! keys[i].valid)
     326         1019 :       continue;
     327            5 :     GNUNET_assert (GNUNET_CRYPTO_BSA_CS ==
     328              :                    keys[i].denom_pub.bsign_pub_key->cipher);
     329            5 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     330              :                 "Requesting R derivation with key %s\n",
     331              :                 GNUNET_h2s (&keys[i].h_cs.hash));
     332              :     {
     333            5 :       struct TALER_CRYPTO_CsDeriveRequest cdr = {
     334            5 :         .h_cs = &keys[i].h_cs,
     335              :         .nonce = &nonce.cs_nonce
     336              :       };
     337              : 
     338            5 :       ec = TALER_CRYPTO_helper_cs_r_batch_derive (
     339              :         dh,
     340              :         1,
     341              :         &cdr,
     342              :         false,
     343              :         &bi.details.cs_values);
     344              :     }
     345            5 :     switch (ec)
     346              :     {
     347            1 :     case TALER_EC_NONE:
     348            1 :       if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_remaining (
     349              :                                       keys[i].start_time.abs_time),
     350              :                                     >,
     351              :                                     GNUNET_TIME_UNIT_SECONDS))
     352              :       {
     353              :         /* key worked too early */
     354            0 :         GNUNET_break (0);
     355            0 :         return 4;
     356              :       }
     357            1 :       if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_duration (
     358              :                                       keys[i].start_time.abs_time),
     359              :                                     >,
     360              :                                     keys[i].validity_duration))
     361              :       {
     362              :         /* key worked too later */
     363            0 :         GNUNET_break (0);
     364            0 :         return 5;
     365              :       }
     366              : 
     367            1 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     368              :                   "Received valid R for key %s\n",
     369              :                   GNUNET_h2s (&keys[i].h_cs.hash));
     370            1 :       TALER_planchet_setup_coin_priv (&ps,
     371              :                                       &alg_values,
     372              :                                       &coin_priv);
     373            1 :       TALER_planchet_blinding_secret_create (&ps,
     374              :                                              &alg_values,
     375              :                                              &bks);
     376            1 :       GNUNET_assert (GNUNET_OK ==
     377              :                      TALER_planchet_prepare (&keys[i].denom_pub,
     378              :                                              &alg_values,
     379              :                                              &bks,
     380              :                                              &nonce,
     381              :                                              &coin_priv,
     382              :                                              NULL, /* no age commitment */
     383              :                                              &c_hash,
     384              :                                              &pd));
     385            1 :       TALER_blinded_planchet_free (&pd.blinded_planchet);
     386            1 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     387              :                   "Successfully prepared planchet");
     388            1 :       success = true;
     389            1 :       break;
     390            4 :     case TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY:
     391              :       /* This 'failure' is expected, we're testing also for the
     392              :          error handling! */
     393            4 :       if ( (GNUNET_TIME_relative_is_zero (
     394              :               GNUNET_TIME_absolute_get_remaining (
     395            0 :                 keys[i].start_time.abs_time))) &&
     396            0 :            (GNUNET_TIME_relative_cmp (
     397              :               GNUNET_TIME_absolute_get_duration (
     398              :                 keys[i].start_time.abs_time),
     399              :               <,
     400              :               keys[i].validity_duration)) )
     401              :       {
     402              :         /* key should have worked! */
     403            0 :         GNUNET_break (0);
     404            0 :         return 6;
     405              :       }
     406            4 :       break;
     407            0 :     default:
     408              :       /* unexpected error */
     409            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     410              :                   "Unexpected error %d\n",
     411              :                   ec);
     412            0 :       return 7;
     413              :     }
     414              :   }
     415            1 :   if (! success)
     416              :   {
     417              :     /* no valid key for signing found, also bad */
     418            0 :     GNUNET_break (0);
     419            0 :     return 16;
     420              :   }
     421              : 
     422              :   /* check R derivation does not work if the key is unknown */
     423              :   {
     424              :     struct TALER_CsPubHashP rnd;
     425              :     struct GNUNET_CRYPTO_CSPublicRPairP crp;
     426            1 :     struct TALER_CRYPTO_CsDeriveRequest cdr = {
     427              :       .h_cs = &rnd,
     428              :       .nonce = &nonce.cs_nonce,
     429              :     };
     430              : 
     431            1 :     GNUNET_CRYPTO_random_block (&rnd,
     432              :                                 sizeof (rnd));
     433            1 :     GNUNET_CRYPTO_random_block (&nonce,
     434              :                                 sizeof (nonce));
     435            1 :     ec = TALER_CRYPTO_helper_cs_r_batch_derive (dh,
     436              :                                                 1,
     437              :                                                 &cdr,
     438              :                                                 false,
     439              :                                                 &crp);
     440            1 :     if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec)
     441              :     {
     442            0 :       GNUNET_break (0);
     443            0 :       return 17;
     444              :     }
     445            1 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     446              :                 "R derivation with invalid key %s failed as desired\n",
     447              :                 GNUNET_h2s (&rnd.hash));
     448              :   }
     449            1 :   return 0;
     450              : }
     451              : 
     452              : 
     453              : /**
     454              :  * Test signing logic.
     455              :  *
     456              :  * @param dh handle to the helper
     457              :  * @return 0 on success
     458              :  */
     459              : static int
     460            1 : test_signing (struct TALER_CRYPTO_CsDenominationHelper *dh)
     461              : {
     462              :   struct TALER_BlindedDenominationSignature ds;
     463              :   enum TALER_ErrorCode ec;
     464            1 :   bool success = false;
     465              :   struct TALER_PlanchetMasterSecretP ps;
     466              :   struct TALER_CoinSpendPrivateKeyP coin_priv;
     467              :   union GNUNET_CRYPTO_BlindingSecretP bks;
     468              :   struct TALER_CoinPubHashP c_hash;
     469            1 :   struct GNUNET_CRYPTO_BlindingInputValues bi = {
     470              :     .cipher = GNUNET_CRYPTO_BSA_CS
     471              :   };
     472            1 :   struct TALER_ExchangeBlindingValues alg_values = {
     473              :     .blinding_inputs = &bi
     474              :   };
     475              :   union GNUNET_CRYPTO_BlindSessionNonce nonce;
     476              : 
     477            1 :   setup_withdraw_secrets (1,
     478              :                           false,
     479              :                           &ps,
     480              :                           &nonce);
     481         1025 :   for (unsigned int i = 0; i<MAX_KEYS; i++)
     482              :   {
     483         1024 :     if (! keys[i].valid)
     484         1019 :       continue;
     485              :     {
     486              :       struct TALER_PlanchetDetail pd;
     487              :       struct TALER_CRYPTO_CsSignRequest csr;
     488            5 :       struct TALER_CRYPTO_CsDeriveRequest cdr = {
     489            5 :         .h_cs = &keys[i].h_cs,
     490              :         .nonce = &nonce.cs_nonce
     491              :       };
     492              : 
     493            5 :       ec = TALER_CRYPTO_helper_cs_r_batch_derive (
     494              :         dh,
     495              :         1,
     496              :         &cdr,
     497              :         false,
     498              :         &bi.details.cs_values);
     499            5 :       if (TALER_EC_NONE != ec)
     500            4 :         continue;
     501            1 :       TALER_planchet_setup_coin_priv (&ps,
     502              :                                       &alg_values,
     503              :                                       &coin_priv);
     504            1 :       TALER_planchet_blinding_secret_create (&ps,
     505              :                                              &alg_values,
     506              :                                              &bks);
     507            1 :       GNUNET_assert (GNUNET_YES ==
     508              :                      TALER_planchet_prepare (&keys[i].denom_pub,
     509              :                                              &alg_values,
     510              :                                              &bks,
     511              :                                              &nonce,
     512              :                                              &coin_priv,
     513              :                                              NULL, /* no age commitment */
     514              :                                              &c_hash,
     515              :                                              &pd));
     516            1 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     517              :                   "Requesting signature with key %s\n",
     518              :                   GNUNET_h2s (&keys[i].h_cs.hash));
     519            1 :       csr.h_cs = &keys[i].h_cs;
     520              :       csr.blinded_planchet
     521            1 :         = &pd.blinded_planchet.blinded_message->details.cs_blinded_message;
     522            1 :       ec = TALER_CRYPTO_helper_cs_batch_sign (
     523              :         dh,
     524              :         1,
     525              :         &csr,
     526              :         false,
     527              :         &ds);
     528            1 :       TALER_blinded_planchet_free (&pd.blinded_planchet);
     529              :     }
     530            1 :     switch (ec)
     531              :     {
     532            1 :     case TALER_EC_NONE:
     533            1 :       if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_remaining (
     534              :                                       keys[i].start_time.abs_time),
     535              :                                     >,
     536              :                                     GNUNET_TIME_UNIT_SECONDS))
     537              :       {
     538              :         /* key worked too early */
     539            0 :         GNUNET_break (0);
     540            0 :         TALER_blinded_denom_sig_free (&ds);
     541            0 :         return 4;
     542              :       }
     543            1 :       if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_duration (
     544              :                                       keys[i].start_time.abs_time),
     545              :                                     >,
     546              :                                     keys[i].validity_duration))
     547              :       {
     548              :         /* key worked too later */
     549            0 :         GNUNET_break (0);
     550            0 :         TALER_blinded_denom_sig_free (&ds);
     551            0 :         return 5;
     552              :       }
     553              :       {
     554              :         struct TALER_FreshCoin coin;
     555              : 
     556            1 :         if (GNUNET_OK !=
     557            1 :             TALER_planchet_to_coin (&keys[i].denom_pub,
     558              :                                     &ds,
     559              :                                     &bks,
     560              :                                     &coin_priv,
     561              :                                     NULL, /* no age commitment */
     562              :                                     &c_hash,
     563              :                                     &alg_values,
     564              :                                     &coin))
     565              :         {
     566            0 :           GNUNET_break (0);
     567            0 :           TALER_blinded_denom_sig_free (&ds);
     568            0 :           return 6;
     569              :         }
     570            1 :         TALER_blinded_denom_sig_free (&ds);
     571            1 :         TALER_denom_sig_free (&coin.sig);
     572              :       }
     573            1 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     574              :                   "Received valid signature for key %s\n",
     575              :                   GNUNET_h2s (&keys[i].h_cs.hash));
     576            1 :       success = true;
     577            1 :       break;
     578            0 :     case TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY:
     579              :       /* This 'failure' is expected, we're testing also for the
     580              :          error handling! */
     581            0 :       if ( (GNUNET_TIME_relative_is_zero (
     582              :               GNUNET_TIME_absolute_get_remaining (
     583            0 :                 keys[i].start_time.abs_time))) &&
     584            0 :            (GNUNET_TIME_relative_cmp (
     585              :               GNUNET_TIME_absolute_get_duration (
     586              :                 keys[i].start_time.abs_time),
     587              :               <,
     588              :               keys[i].validity_duration)) )
     589              :       {
     590              :         /* key should have worked! */
     591            0 :         GNUNET_break (0);
     592            0 :         return 6;
     593              :       }
     594            0 :       break;
     595            0 :     default:
     596              :       /* unexpected error */
     597            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     598              :                   "Unexpected error %d\n",
     599              :                   ec);
     600            0 :       return 7;
     601              :     }
     602              :   }
     603            1 :   if (! success)
     604              :   {
     605              :     /* no valid key for signing found, also bad */
     606            0 :     GNUNET_break (0);
     607            0 :     return 16;
     608              :   }
     609              : 
     610              :   /* check signing does not work if the key is unknown */
     611              :   {
     612              :     struct TALER_PlanchetDetail pd;
     613              :     struct TALER_CsPubHashP rnd;
     614              :     struct TALER_CRYPTO_CsSignRequest csr;
     615              : 
     616            1 :     GNUNET_CRYPTO_random_block (&rnd,
     617              :                                 sizeof (rnd));
     618            1 :     GNUNET_assert (GNUNET_YES ==
     619              :                    TALER_planchet_prepare (&keys[0].denom_pub,
     620              :                                            &alg_values,
     621              :                                            &bks,
     622              :                                            &nonce,
     623              :                                            &coin_priv,
     624              :                                            NULL, /* no age commitment */
     625              :                                            &c_hash,
     626              :                                            &pd));
     627            1 :     csr.h_cs = &rnd;
     628              :     csr.blinded_planchet
     629            1 :       = &pd.blinded_planchet.blinded_message->details.cs_blinded_message;
     630            1 :     ec = TALER_CRYPTO_helper_cs_batch_sign (
     631              :       dh,
     632              :       1,
     633              :       &csr,
     634              :       false,
     635              :       &ds);
     636            1 :     TALER_blinded_planchet_free (&pd.blinded_planchet);
     637            1 :     if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec)
     638              :     {
     639            0 :       if (TALER_EC_NONE == ec)
     640            0 :         TALER_blinded_denom_sig_free (&ds);
     641            0 :       GNUNET_break (0);
     642            0 :       return 17;
     643              :     }
     644            1 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     645              :                 "Signing with invalid key %s failed as desired\n",
     646              :                 GNUNET_h2s (&rnd.hash));
     647              :   }
     648            1 :   return 0;
     649              : }
     650              : 
     651              : 
     652              : /**
     653              :  * Test batch signing logic.
     654              :  *
     655              :  * @param dh handle to the helper
     656              :  * @param batch_size how large should the batch be
     657              :  * @param check_sigs also check unknown key and signatures
     658              :  * @return 0 on success
     659              :  */
     660              : static int
     661            6 : test_batch_signing (struct TALER_CRYPTO_CsDenominationHelper *dh,
     662              :                     unsigned int batch_size,
     663              :                     bool check_sigs)
     664            6 : {
     665            6 :   struct TALER_BlindedDenominationSignature ds[batch_size];
     666              :   enum TALER_ErrorCode ec;
     667            6 :   bool success = false;
     668            6 :   struct TALER_PlanchetMasterSecretP ps[batch_size];
     669            6 :   struct TALER_CoinSpendPrivateKeyP coin_priv[batch_size];
     670            6 :   union GNUNET_CRYPTO_BlindingSecretP bks[batch_size];
     671            6 :   struct TALER_CoinPubHashP c_hash[batch_size];
     672            6 :   struct GNUNET_CRYPTO_BlindingInputValues bi[batch_size];
     673            6 :   struct TALER_ExchangeBlindingValues alg_values[batch_size];
     674            6 :   union GNUNET_CRYPTO_BlindSessionNonce nonces[batch_size];
     675              : 
     676            6 :   setup_withdraw_secrets (batch_size,
     677              :                           false,
     678              :                           ps,
     679              :                           nonces);
     680         6150 :   for (unsigned int k = 0; k<MAX_KEYS; k++)
     681              :   {
     682         6144 :     if (! keys[k].valid)
     683         6114 :       continue;
     684           30 :     {
     685           30 :       struct TALER_PlanchetDetail pd[batch_size];
     686           30 :       struct TALER_CRYPTO_CsSignRequest csr[batch_size];
     687           30 :       struct TALER_CRYPTO_CsDeriveRequest cdr[batch_size];
     688           30 :       struct GNUNET_CRYPTO_CSPublicRPairP crps[batch_size];
     689              : 
     690          785 :       for (unsigned int i = 0; i<batch_size; i++)
     691              :       {
     692          755 :         cdr[i].h_cs = &keys[k].h_cs;
     693          755 :         cdr[i].nonce = &nonces[i].cs_nonce;
     694          755 :         bi[i].cipher = GNUNET_CRYPTO_BSA_CS;
     695          755 :         alg_values[i].blinding_inputs = &bi[i];
     696              :       }
     697           30 :       ec = TALER_CRYPTO_helper_cs_r_batch_derive (
     698              :         dh,
     699              :         batch_size,
     700              :         cdr,
     701              :         false,
     702              :         crps);
     703           30 :       if (TALER_EC_NONE != ec)
     704           24 :         continue;
     705          157 :       for (unsigned int i = 0; i<batch_size; i++)
     706              :       {
     707          151 :         bi[i].details.cs_values = crps[i];
     708          151 :         TALER_planchet_setup_coin_priv (&ps[i],
     709          151 :                                         &alg_values[i],
     710              :                                         &coin_priv[i]);
     711          151 :         TALER_planchet_blinding_secret_create (&ps[i],
     712          151 :                                                &alg_values[i],
     713              :                                                &bks[i]);
     714          151 :         GNUNET_assert (GNUNET_YES ==
     715              :                        TALER_planchet_prepare (&keys[k].denom_pub,
     716              :                                                &alg_values[i],
     717              :                                                &bks[i],
     718              :                                                &nonces[i],
     719              :                                                &coin_priv[i],
     720              :                                                NULL, /* no age commitment */
     721              :                                                &c_hash[i],
     722              :                                                &pd[i]));
     723          151 :         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     724              :                     "Requesting signature with key %s\n",
     725              :                     GNUNET_h2s (&keys[k].h_cs.hash));
     726          151 :         csr[i].h_cs = &keys[k].h_cs;
     727              :         csr[i].blinded_planchet
     728          151 :           = &pd[i].blinded_planchet.blinded_message->details.cs_blinded_message;
     729              :       }
     730            6 :       ec = TALER_CRYPTO_helper_cs_batch_sign (
     731              :         dh,
     732              :         batch_size,
     733              :         csr,
     734              :         false,
     735              :         ds);
     736          157 :       for (unsigned int i = 0; i<batch_size; i++)
     737              :       {
     738          151 :         TALER_blinded_planchet_free (&pd[i].blinded_planchet);
     739              :       }
     740              :     }
     741            6 :     switch (ec)
     742              :     {
     743            6 :     case TALER_EC_NONE:
     744            6 :       if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_remaining (
     745              :                                       keys[k].start_time.abs_time),
     746              :                                     >,
     747              :                                     GNUNET_TIME_UNIT_SECONDS))
     748              :       {
     749              :         /* key worked too early */
     750            0 :         GNUNET_break (0);
     751            0 :         return 4;
     752              :       }
     753            6 :       if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_duration (
     754              :                                       keys[k].start_time.abs_time),
     755              :                                     >,
     756              :                                     keys[k].validity_duration))
     757              :       {
     758              :         /* key worked too later */
     759            0 :         GNUNET_break (0);
     760            0 :         return 5;
     761              :       }
     762            6 :       if (check_sigs)
     763              :       {
     764           68 :         for (unsigned int i = 0; i<batch_size; i++)
     765              :         {
     766              :           struct TALER_FreshCoin coin;
     767              : 
     768           66 :           if (GNUNET_OK !=
     769           66 :               TALER_planchet_to_coin (&keys[k].denom_pub,
     770           66 :                                       &ds[i],
     771           66 :                                       &bks[i],
     772           66 :                                       &coin_priv[i],
     773              :                                       NULL, /* no age commitment */
     774           66 :                                       &c_hash[i],
     775           66 :                                       &alg_values[i],
     776              :                                       &coin))
     777              :           {
     778            0 :             GNUNET_break (0);
     779            0 :             return 6;
     780              :           }
     781           66 :           TALER_blinded_denom_sig_free (&ds[i]);
     782           66 :           TALER_denom_sig_free (&coin.sig);
     783              :         }
     784            2 :         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     785              :                     "Received valid signature for key %s\n",
     786              :                     GNUNET_h2s (&keys[k].h_cs.hash));
     787              :       }
     788              :       else
     789              :       {
     790           89 :         for (unsigned int i = 0; i<batch_size; i++)
     791           85 :           TALER_blinded_denom_sig_free (&ds[i]);
     792              :       }
     793            6 :       success = true;
     794            6 :       break;
     795            0 :     case TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY:
     796              :       /* This 'failure' is expected, we're testing also for the
     797              :          error handling! */
     798            0 :       if ( (GNUNET_TIME_relative_is_zero (
     799              :               GNUNET_TIME_absolute_get_remaining (
     800            0 :                 keys[k].start_time.abs_time))) &&
     801            0 :            (GNUNET_TIME_relative_cmp (
     802              :               GNUNET_TIME_absolute_get_duration (
     803              :                 keys[k].start_time.abs_time),
     804              :               <,
     805              :               keys[k].validity_duration)) )
     806              :       {
     807              :         /* key should have worked! */
     808            0 :         GNUNET_break (0);
     809            0 :         return 6;
     810              :       }
     811            0 :       break;
     812            0 :     default:
     813              :       /* unexpected error */
     814            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     815              :                   "Unexpected error %d\n",
     816              :                   ec);
     817            0 :       return 7;
     818              :     }
     819              :   }
     820            6 :   if (! success)
     821              :   {
     822              :     /* no valid key for signing found, also bad */
     823            0 :     GNUNET_break (0);
     824            0 :     return 16;
     825              :   }
     826              : 
     827              :   /* check signing does not work if the key is unknown */
     828            6 :   if (check_sigs)
     829              :   {
     830              :     struct TALER_PlanchetDetail pd;
     831              :     struct TALER_CsPubHashP rnd;
     832              :     struct TALER_CRYPTO_CsSignRequest csr;
     833              : 
     834            2 :     GNUNET_CRYPTO_random_block (&rnd,
     835              :                                 sizeof (rnd));
     836            2 :     GNUNET_assert (GNUNET_YES ==
     837              :                    TALER_planchet_prepare (&keys[0].denom_pub,
     838              :                                            &alg_values[0],
     839              :                                            &bks[0],
     840              :                                            &nonces[0],
     841              :                                            &coin_priv[0],
     842              :                                            NULL, /* no age commitment */
     843              :                                            &c_hash[0],
     844              :                                            &pd));
     845            2 :     csr.h_cs = &rnd;
     846              :     csr.blinded_planchet
     847            2 :       = &pd.blinded_planchet.blinded_message->details.cs_blinded_message;
     848            2 :     ec = TALER_CRYPTO_helper_cs_batch_sign (
     849              :       dh,
     850              :       1,
     851              :       &csr,
     852              :       false,
     853              :       &ds[0]);
     854            2 :     TALER_blinded_planchet_free (&pd.blinded_planchet);
     855            2 :     if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec)
     856              :     {
     857            0 :       if (TALER_EC_NONE == ec)
     858            0 :         TALER_blinded_denom_sig_free (&ds[0]);
     859            0 :       GNUNET_break (0);
     860            0 :       return 17;
     861              :     }
     862            2 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     863              :                 "Signing with invalid key %s failed as desired\n",
     864              :                 GNUNET_h2s (&rnd.hash));
     865              :   }
     866            6 :   return 0;
     867              : }
     868              : 
     869              : 
     870              : /**
     871              :  * Benchmark signing logic.
     872              :  *
     873              :  * @param dh handle to the helper
     874              :  * @return 0 on success
     875              :  */
     876              : static int
     877            9 : perf_signing (struct TALER_CRYPTO_CsDenominationHelper *dh,
     878              :               const char *type)
     879              : {
     880              :   struct TALER_BlindedDenominationSignature ds;
     881              :   enum TALER_ErrorCode ec;
     882              :   struct GNUNET_TIME_Relative duration;
     883              :   struct TALER_PlanchetMasterSecretP ps;
     884              :   struct TALER_CoinSpendPrivateKeyP coin_priv;
     885              :   union GNUNET_CRYPTO_BlindingSecretP bks;
     886            9 :   struct GNUNET_CRYPTO_BlindingInputValues bv = {
     887              :     .cipher = GNUNET_CRYPTO_BSA_CS
     888              :   };
     889            9 :   struct TALER_ExchangeBlindingValues alg_values = {
     890              :     .blinding_inputs = &bv
     891              :   };
     892              :   union GNUNET_CRYPTO_BlindSessionNonce nonce;
     893              : 
     894            9 :   setup_withdraw_secrets (1,
     895              :                           true,
     896              :                           &ps,
     897              :                           &nonce);
     898            9 :   duration = GNUNET_TIME_UNIT_ZERO;
     899            9 :   TALER_CRYPTO_helper_cs_poll (dh);
     900           18 :   for (unsigned int j = 0; j<NUM_SIGN_PERFS;)
     901              :   {
     902         9225 :     for (unsigned int i = 0; i<MAX_KEYS; i++)
     903              :     {
     904         9216 :       if (! keys[i].valid)
     905         9147 :         continue;
     906           69 :       if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_remaining (
     907              :                                       keys[i].start_time.abs_time),
     908              :                                     >,
     909              :                                     GNUNET_TIME_UNIT_SECONDS))
     910           52 :         continue;
     911           17 :       if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_duration (
     912              :                                       keys[i].start_time.abs_time),
     913              :                                     >,
     914              :                                     keys[i].validity_duration))
     915            0 :         continue;
     916              :       {
     917              :         struct TALER_CoinPubHashP c_hash;
     918              :         struct TALER_PlanchetDetail pd;
     919           17 :         struct TALER_CRYPTO_CsDeriveRequest cdr = {
     920           17 :           .h_cs = &keys[i].h_cs,
     921              :           .nonce = &nonce.cs_nonce
     922              :         };
     923              : 
     924           17 :         ec = TALER_CRYPTO_helper_cs_r_batch_derive (
     925              :           dh,
     926              :           1,
     927              :           &cdr,
     928              :           true,
     929              :           &bv.details.cs_values);
     930           17 :         if (TALER_EC_NONE != ec)
     931            8 :           continue;
     932            9 :         TALER_planchet_setup_coin_priv (&ps,
     933              :                                         &alg_values,
     934              :                                         &coin_priv);
     935            9 :         TALER_planchet_blinding_secret_create (&ps,
     936              :                                                &alg_values,
     937              :                                                &bks);
     938            9 :         GNUNET_assert (GNUNET_YES ==
     939              :                        TALER_planchet_prepare (&keys[i].denom_pub,
     940              :                                                &alg_values,
     941              :                                                &bks,
     942              :                                                &nonce,
     943              :                                                &coin_priv,
     944              :                                                NULL, /* no age commitment */
     945              :                                                &c_hash,
     946              :                                                &pd));
     947              :         /* use this key as long as it works */
     948              :         while (1)
     949          891 :         {
     950          900 :           struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get ();
     951              :           struct GNUNET_TIME_Relative delay;
     952              :           struct TALER_CRYPTO_CsSignRequest csr;
     953              : 
     954          900 :           csr.h_cs = &keys[i].h_cs;
     955              :           csr.blinded_planchet
     956          900 :             = &pd.blinded_planchet.blinded_message->details.cs_blinded_message;
     957          900 :           ec = TALER_CRYPTO_helper_cs_batch_sign (
     958              :             dh,
     959              :             1,
     960              :             &csr,
     961              :             true,
     962              :             &ds);
     963          900 :           if (TALER_EC_NONE != ec)
     964            0 :             break;
     965          900 :           delay = GNUNET_TIME_absolute_get_duration (start);
     966          900 :           duration = GNUNET_TIME_relative_add (duration,
     967              :                                                delay);
     968          900 :           TALER_blinded_denom_sig_free (&ds);
     969          900 :           j++;
     970          900 :           if (NUM_SIGN_PERFS <= j)
     971            9 :             break;
     972              :         }
     973            9 :         TALER_blinded_planchet_free (&pd.blinded_planchet);
     974              :       }
     975              :     }   /* for i */
     976              :   }   /* for j */
     977            9 :   fprintf (stderr,
     978              :            "%u (%s) signature operations took %s\n",
     979              :            (unsigned int) NUM_SIGN_PERFS,
     980              :            type,
     981              :            GNUNET_STRINGS_relative_time_to_string (duration,
     982              :                                                    GNUNET_YES));
     983            9 :   return 0;
     984              : }
     985              : 
     986              : 
     987              : /**
     988              :  * Parallel signing logic.
     989              :  *
     990              :  * @param esh handle to the helper
     991              :  * @return 0 on success
     992              :  */
     993              : static int
     994            1 : par_signing (struct GNUNET_CONFIGURATION_Handle *cfg)
     995              : {
     996              :   struct GNUNET_TIME_Absolute start;
     997              :   struct GNUNET_TIME_Relative duration;
     998              :   pid_t pids[NUM_CORES];
     999              :   struct TALER_CRYPTO_CsDenominationHelper *dh;
    1000              : 
    1001            1 :   start = GNUNET_TIME_absolute_get ();
    1002            9 :   for (unsigned int i = 0; i<NUM_CORES; i++)
    1003              :   {
    1004            8 :     pids[i] = fork ();
    1005           16 :     num_keys = 0;
    1006           16 :     GNUNET_assert (-1 != pids[i]);
    1007           16 :     if (0 == pids[i])
    1008              :     {
    1009              :       int ret;
    1010              : 
    1011            8 :       dh = TALER_CRYPTO_helper_cs_connect (cfg,
    1012              :                                            "taler-exchange",
    1013              :                                            &key_cb,
    1014              :                                            NULL);
    1015            8 :       GNUNET_assert (NULL != dh);
    1016            8 :       ret = perf_signing (dh,
    1017              :                           "parallel");
    1018            8 :       TALER_CRYPTO_helper_cs_disconnect (dh);
    1019            8 :       free_keys ();
    1020            8 :       exit (ret);
    1021              :     }
    1022              :   }
    1023            9 :   for (unsigned int i = 0; i<NUM_CORES; i++)
    1024              :   {
    1025              :     int wstatus;
    1026              : 
    1027            8 :     GNUNET_assert (pids[i] ==
    1028              :                    waitpid (pids[i],
    1029              :                             &wstatus,
    1030              :                             0));
    1031              :   }
    1032            1 :   duration = GNUNET_TIME_absolute_get_duration (start);
    1033            1 :   fprintf (stderr,
    1034              :            "%u (parallel) signature operations took %s (total real time)\n",
    1035              :            (unsigned int) NUM_SIGN_PERFS * NUM_CORES,
    1036              :            GNUNET_STRINGS_relative_time_to_string (duration,
    1037              :                                                    GNUNET_YES));
    1038            1 :   return 0;
    1039              : }
    1040              : 
    1041              : 
    1042              : /**
    1043              :  * Main entry point into the test logic with the helper already running.
    1044              :  */
    1045              : static int
    1046            1 : run_test (void)
    1047              : {
    1048              :   struct GNUNET_CONFIGURATION_Handle *cfg;
    1049              :   struct TALER_CRYPTO_CsDenominationHelper *dh;
    1050            1 :   struct timespec req = {
    1051              :     .tv_nsec = 250000000
    1052              :   };
    1053              :   int ret;
    1054              : 
    1055            1 :   cfg = GNUNET_CONFIGURATION_create (TALER_EXCHANGE_project_data ());
    1056            1 :   if (GNUNET_OK !=
    1057            1 :       GNUNET_CONFIGURATION_load (cfg,
    1058              :                                  "test_helper_cs.conf"))
    1059              :   {
    1060            0 :     GNUNET_break (0);
    1061            0 :     return 77;
    1062              :   }
    1063              : 
    1064            1 :   fprintf (stderr, "Waiting for helper to start ... ");
    1065            1 :   for (unsigned int i = 0; i<100; i++)
    1066              :   {
    1067            1 :     nanosleep (&req,
    1068              :                NULL);
    1069            1 :     dh = TALER_CRYPTO_helper_cs_connect (cfg,
    1070              :                                          "taler-exchange",
    1071              :                                          &key_cb,
    1072              :                                          NULL);
    1073            1 :     if (NULL != dh)
    1074            1 :       break;
    1075            0 :     fprintf (stderr, ".");
    1076              :   }
    1077            1 :   if (NULL == dh)
    1078              :   {
    1079            0 :     fprintf (stderr,
    1080              :              "\nFAILED: timeout trying to connect to helper\n");
    1081            0 :     GNUNET_CONFIGURATION_destroy (cfg);
    1082            0 :     return 1;
    1083              :   }
    1084            1 :   if (0 == num_keys)
    1085              :   {
    1086            0 :     fprintf (stderr,
    1087              :              "\nFAILED: timeout trying to connect to helper\n");
    1088            0 :     TALER_CRYPTO_helper_cs_disconnect (dh);
    1089            0 :     GNUNET_CONFIGURATION_destroy (cfg);
    1090            0 :     return 1;
    1091              :   }
    1092            1 :   fprintf (stderr,
    1093              :            " Done (%u keys)\n",
    1094              :            num_keys);
    1095            1 :   ret = 0;
    1096            1 :   if (0 == ret)
    1097            1 :     ret = test_revocation (dh);
    1098            1 :   if (0 == ret)
    1099            1 :     ret = test_r_derive (dh);
    1100            1 :   if (0 == ret)
    1101            1 :     ret = test_signing (dh);
    1102            1 :   if (0 == ret)
    1103            1 :     ret = test_batch_signing (dh,
    1104              :                               2,
    1105              :                               true);
    1106            1 :   if (0 == ret)
    1107            1 :     ret = test_batch_signing (dh,
    1108              :                               64,
    1109              :                               true);
    1110            5 :   for (unsigned int i = 0; i<4; i++)
    1111              :   {
    1112              :     static unsigned int batches[] = { 1, 4, 16, 64 };
    1113            4 :     unsigned int batch_size = batches[i];
    1114              :     struct GNUNET_TIME_Absolute start;
    1115              :     struct GNUNET_TIME_Relative duration;
    1116              : 
    1117            4 :     start = GNUNET_TIME_absolute_get ();
    1118            4 :     if (0 != ret)
    1119            0 :       break;
    1120            4 :     ret = test_batch_signing (dh,
    1121              :                               batch_size,
    1122              :                               false);
    1123            4 :     duration = GNUNET_TIME_absolute_get_duration (start);
    1124            4 :     fprintf (stderr,
    1125              :              "%4u (batch) signature operations took %s (total real time)\n",
    1126              :              (unsigned int) batch_size,
    1127              :              GNUNET_STRINGS_relative_time_to_string (duration,
    1128              :                                                      GNUNET_YES));
    1129              :   }
    1130            1 :   if (0 == ret)
    1131            1 :     ret = perf_signing (dh,
    1132              :                         "sequential");
    1133            1 :   TALER_CRYPTO_helper_cs_disconnect (dh);
    1134            1 :   free_keys ();
    1135            1 :   if (0 == ret)
    1136            1 :     ret = par_signing (cfg);
    1137              :   /* clean up our state */
    1138            1 :   GNUNET_CONFIGURATION_destroy (cfg);
    1139            1 :   return ret;
    1140              : }
    1141              : 
    1142              : 
    1143              : int
    1144            1 : main (int argc,
    1145              :       const char *const argv[])
    1146              : {
    1147              :   struct GNUNET_Process *helper;
    1148              :   char *libexec_dir;
    1149              :   char *binary_name;
    1150              :   int ret;
    1151              :   enum GNUNET_OS_ProcessStatusType type;
    1152              :   unsigned long code;
    1153            1 :   const char *loglev = "WARNING";
    1154              : 
    1155              :   (void) argc;
    1156              :   (void) argv;
    1157            1 :   unsetenv ("XDG_DATA_HOME");
    1158            1 :   unsetenv ("XDG_CONFIG_HOME");
    1159            1 :   GNUNET_log_setup ("test-helper-cs",
    1160              :                     loglev,
    1161              :                     NULL);
    1162            1 :   libexec_dir = GNUNET_OS_installation_get_path (TALER_EXCHANGE_project_data (),
    1163              :                                                  GNUNET_OS_IPK_BINDIR);
    1164            1 :   GNUNET_asprintf (&binary_name,
    1165              :                    "%s/%s",
    1166              :                    libexec_dir,
    1167              :                    "taler-exchange-secmod-cs");
    1168            1 :   GNUNET_free (libexec_dir);
    1169            1 :   helper = GNUNET_process_create (GNUNET_OS_INHERIT_STD_ERR);
    1170            1 :   if (GNUNET_OK !=
    1171            1 :       GNUNET_process_run_command_va (helper,
    1172              :                                      binary_name,
    1173              :                                      binary_name,
    1174              :                                      "-c",
    1175              :                                      "test_helper_cs.conf",
    1176              :                                      "-L",
    1177              :                                      loglev,
    1178              :                                      NULL))
    1179              :   {
    1180            0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
    1181              :                               "exec",
    1182              :                               binary_name);
    1183            0 :     GNUNET_process_destroy (helper);
    1184            0 :     GNUNET_free (binary_name);
    1185            0 :     return 77;
    1186              :   }
    1187            1 :   GNUNET_free (binary_name);
    1188            1 :   ret = run_test ();
    1189              : 
    1190            1 :   GNUNET_break (GNUNET_OK ==
    1191              :                 GNUNET_process_kill (helper,
    1192              :                                      SIGTERM));
    1193            1 :   if (GNUNET_OK !=
    1194            1 :       GNUNET_process_wait (helper,
    1195              :                            true,
    1196              :                            &type,
    1197              :                            &code))
    1198              :   {
    1199            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1200              :                 "Helper process did not die voluntarily, killing hard\n");
    1201            0 :     GNUNET_break (GNUNET_OK ==
    1202              :                   GNUNET_process_kill (helper,
    1203              :                                        SIGKILL));
    1204            0 :     ret = 4;
    1205              :   }
    1206            1 :   else if ( (GNUNET_OS_PROCESS_EXITED != type) ||
    1207            1 :             (0 != code) )
    1208              :   {
    1209            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1210              :                 "Helper died with unexpected status %d/%d\n",
    1211              :                 (int) type,
    1212              :                 (int) code);
    1213            0 :     ret = 5;
    1214              :   }
    1215            1 :   GNUNET_process_destroy (helper);
    1216            1 :   return ret;
    1217              : }
    1218              : 
    1219              : 
    1220              : /* end of test_helper_cs.c */
        

Generated by: LCOV version 2.0-1