LCOV - code coverage report
Current view: top level - util - test_helper_rsa.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 77.5 % 365 283
Test Date: 2026-05-12 15:34:29 Functions: 100.0 % 9 9

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   (C) 2020, 2021, 2022 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_rsa.c
      18              :  * @brief Tests for RSA 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_RsaPubHashP h_rsa;
      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_rsa 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_RsaPubHashP *h_rsa,
     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_rsa->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           10 :     for (unsigned int i = 0; i<MAX_KEYS; i++)
     161           10 :       if (0 == GNUNET_memcmp (h_rsa,
     162              :                               &keys[i].h_rsa))
     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          313 :   for (unsigned int i = 0; i<MAX_KEYS; i++)
     181          313 :     if (! keys[i].valid)
     182              :     {
     183           72 :       keys[i].valid = true;
     184           72 :       keys[i].h_rsa = *h_rsa;
     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_RsaDenominationHelper *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 (GNUNET_CRYPTO_QUALITY_WEAK,
     217              :                                     num_keys);
     218              :     /* find index of key to revoke */
     219           10 :     for (unsigned int j = 0; j < MAX_KEYS; j++)
     220              :     {
     221           10 :       if (! keys[j].valid)
     222            0 :         continue;
     223           10 :       if (0 != off)
     224              :       {
     225            7 :         off--;
     226            7 :         continue;
     227              :       }
     228            3 :       keys[j].revoked = true;
     229            3 :       fprintf (stderr,
     230              :                "Revoking key %s ...",
     231            3 :                GNUNET_h2s (&keys[j].h_rsa.hash));
     232            3 :       TALER_CRYPTO_helper_rsa_revoke (dh,
     233            3 :                                       &keys[j].h_rsa);
     234            6 :       for (unsigned int k = 0; k<1000; k++)
     235              :       {
     236            6 :         TALER_CRYPTO_helper_rsa_poll (dh);
     237            6 :         if (! keys[j].revoked)
     238            3 :           break;
     239            3 :         nanosleep (&req, NULL);
     240            3 :         fprintf (stderr, ".");
     241              :       }
     242            3 :       if (keys[j].revoked)
     243              :       {
     244            0 :         fprintf (stderr,
     245              :                  "\nFAILED: timeout trying to revoke key %u\n",
     246              :                  j);
     247            0 :         TALER_CRYPTO_helper_rsa_disconnect (dh);
     248            0 :         return 2;
     249              :       }
     250            3 :       fprintf (stderr, "\n");
     251            3 :       break;
     252              :     }
     253              :   }
     254            1 :   return 0;
     255              : }
     256              : 
     257              : 
     258              : /**
     259              :  * Test signing logic.
     260              :  *
     261              :  * @param dh handle to the helper
     262              :  * @return 0 on success
     263              :  */
     264              : static int
     265            1 : test_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh)
     266              : {
     267              :   struct TALER_BlindedDenominationSignature ds;
     268              :   enum TALER_ErrorCode ec;
     269            1 :   bool success = false;
     270              :   struct TALER_PlanchetMasterSecretP ps;
     271              :   const struct TALER_ExchangeBlindingValues *alg_values
     272            1 :     = TALER_denom_ewv_rsa_singleton ();
     273              :   struct TALER_AgeCommitmentHashP ach;
     274              :   struct TALER_CoinPubHashP c_hash;
     275              :   struct TALER_CoinSpendPrivateKeyP coin_priv;
     276              :   union GNUNET_CRYPTO_BlindingSecretP bks;
     277              : 
     278            1 :   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
     279              :                               &ps,
     280              :                               sizeof (ps));
     281            1 :   TALER_planchet_setup_coin_priv (&ps,
     282              :                                   alg_values,
     283              :                                   &coin_priv);
     284            1 :   TALER_planchet_blinding_secret_create (&ps,
     285              :                                          alg_values,
     286              :                                          &bks);
     287            1 :   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
     288              :                               &ach,
     289              :                               sizeof(ach));
     290              : 
     291         1025 :   for (unsigned int i = 0; i<MAX_KEYS; i++)
     292              :   {
     293         1024 :     if (! keys[i].valid)
     294         1019 :       continue;
     295            5 :     if (GNUNET_CRYPTO_BSA_RSA !=
     296            5 :         keys[i].denom_pub.bsign_pub_key->cipher)
     297            0 :       continue;
     298              :     {
     299              :       struct TALER_PlanchetDetail pd;
     300              : 
     301            5 :       GNUNET_assert (GNUNET_YES ==
     302              :                      TALER_planchet_prepare (&keys[i].denom_pub,
     303              :                                              alg_values,
     304              :                                              &bks,
     305              :                                              NULL,
     306              :                                              &coin_priv,
     307              :                                              &ach,
     308              :                                              &c_hash,
     309              :                                              &pd));
     310              :       {
     311            5 :         struct TALER_CRYPTO_RsaSignRequest rsr = {
     312            5 :           .h_rsa = &keys[i].h_rsa,
     313              :           .msg =
     314            5 :             pd.blinded_planchet.blinded_message->details.rsa_blinded_message.
     315              :             blinded_msg,
     316              :           .msg_size =
     317            5 :             pd.blinded_planchet.blinded_message->details.rsa_blinded_message.
     318              :             blinded_msg_size
     319              :         };
     320              : 
     321            5 :         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     322              :                     "Requesting signature over %u bytes with key %s\n",
     323              :                     (unsigned int) rsr.msg_size,
     324              :                     GNUNET_h2s (&rsr.h_rsa->hash));
     325            5 :         ec = TALER_CRYPTO_helper_rsa_batch_sign (dh,
     326              :                                                  1,
     327              :                                                  &rsr,
     328              :                                                  &ds);
     329              :       }
     330            5 :       TALER_blinded_planchet_free (&pd.blinded_planchet);
     331              :     }
     332            5 :     switch (ec)
     333              :     {
     334            1 :     case TALER_EC_NONE:
     335            1 :       if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_remaining (
     336              :                                       keys[i].start_time.abs_time),
     337              :                                     >,
     338              :                                     GNUNET_TIME_UNIT_SECONDS))
     339              :       {
     340              :         /* key worked too early */
     341            0 :         GNUNET_break (0);
     342            0 :         return 4;
     343              :       }
     344            1 :       if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_duration (
     345              :                                       keys[i].start_time.abs_time),
     346              :                                     >,
     347              :                                     keys[i].validity_duration))
     348              :       {
     349              :         /* key worked too later */
     350            0 :         GNUNET_break (0);
     351            0 :         return 5;
     352              :       }
     353              :       {
     354              :         struct TALER_DenominationSignature rs;
     355              : 
     356            1 :         if (GNUNET_OK !=
     357            1 :             TALER_denom_sig_unblind (&rs,
     358              :                                      &ds,
     359              :                                      &bks,
     360              :                                      &c_hash,
     361              :                                      alg_values,
     362            1 :                                      &keys[i].denom_pub))
     363              :         {
     364            0 :           GNUNET_break (0);
     365            0 :           return 6;
     366              :         }
     367            1 :         TALER_blinded_denom_sig_free (&ds);
     368            1 :         if (GNUNET_OK !=
     369            1 :             TALER_denom_pub_verify (&keys[i].denom_pub,
     370              :                                     &rs,
     371              :                                     &c_hash))
     372              :         {
     373              :           /* signature invalid */
     374            0 :           GNUNET_break (0);
     375            0 :           TALER_denom_sig_free (&rs);
     376            0 :           return 7;
     377              :         }
     378            1 :         TALER_denom_sig_free (&rs);
     379              :       }
     380            1 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     381              :                   "Received valid signature for key %s\n",
     382              :                   GNUNET_h2s (&keys[i].h_rsa.hash));
     383            1 :       success = true;
     384            1 :       break;
     385            4 :     case TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY:
     386              :       /* This 'failure' is expected, we're testing also for the
     387              :          error handling! */
     388            4 :       if ( (GNUNET_TIME_relative_is_zero (
     389              :               GNUNET_TIME_absolute_get_remaining (
     390            0 :                 keys[i].start_time.abs_time))) &&
     391            0 :            (GNUNET_TIME_relative_cmp (
     392              :               GNUNET_TIME_absolute_get_duration (
     393              :                 keys[i].start_time.abs_time),
     394              :               <,
     395              :               keys[i].validity_duration)) )
     396              :       {
     397              :         /* key should have worked! */
     398            0 :         GNUNET_break (0);
     399            0 :         return 6;
     400              :       }
     401            4 :       break;
     402            0 :     default:
     403              :       /* unexpected error */
     404            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     405              :                   "Unexpected error %d at %s:%u\n",
     406              :                   ec,
     407              :                   __FILE__,
     408              :                   __LINE__);
     409            0 :       return 7;
     410              :     }
     411              :   }
     412            1 :   if (! success)
     413              :   {
     414              :     /* no valid key for signing found, also bad */
     415            0 :     GNUNET_break (0);
     416            0 :     return 16;
     417              :   }
     418              : 
     419              :   /* check signing does not work if the key is unknown */
     420              :   {
     421              :     struct TALER_RsaPubHashP rnd;
     422            1 :     struct TALER_CRYPTO_RsaSignRequest rsr = {
     423              :       .h_rsa = &rnd,
     424              :       .msg = "Hello",
     425              :       .msg_size = strlen ("Hello")
     426              :     };
     427              : 
     428            1 :     GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
     429              :                                 &rnd,
     430              :                                 sizeof (rnd));
     431            1 :     ec = TALER_CRYPTO_helper_rsa_batch_sign (dh,
     432              :                                              1,
     433              :                                              &rsr,
     434              :                                              &ds);
     435            1 :     if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec)
     436              :     {
     437            0 :       if (TALER_EC_NONE == ec)
     438            0 :         TALER_blinded_denom_sig_free (&ds);
     439            0 :       GNUNET_break (0);
     440            0 :       return 17;
     441              :     }
     442            1 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     443              :                 "Signing with invalid key %s failed as desired\n",
     444              :                 GNUNET_h2s (&rnd.hash));
     445              :   }
     446            1 :   return 0;
     447              : }
     448              : 
     449              : 
     450              : /**
     451              :  * Test batch signing logic.
     452              :  *
     453              :  * @param dh handle to the helper
     454              :  * @param batch_size how large should the batch be
     455              :  * @param check_sigs also check unknown key and signatures
     456              :  * @return 0 on success
     457              :  */
     458              : static int
     459            6 : test_batch_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh,
     460              :                     unsigned int batch_size,
     461              :                     bool check_sigs)
     462            6 : {
     463            6 :   struct TALER_BlindedDenominationSignature ds[batch_size];
     464              :   enum TALER_ErrorCode ec;
     465            6 :   bool success = false;
     466            6 :   struct TALER_PlanchetMasterSecretP ps[batch_size];
     467              :   const struct TALER_ExchangeBlindingValues *alg_values;
     468            6 :   struct TALER_AgeCommitmentHashP ach[batch_size];
     469            6 :   struct TALER_CoinPubHashP c_hash[batch_size];
     470            6 :   struct TALER_CoinSpendPrivateKeyP coin_priv[batch_size];
     471            6 :   union GNUNET_CRYPTO_BlindingSecretP bks[batch_size];
     472              : 
     473            6 :   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
     474              :                               &ps,
     475              :                               sizeof (ps));
     476            6 :   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
     477              :                               &ach,
     478              :                               sizeof(ach));
     479            6 :   alg_values = TALER_denom_ewv_rsa_singleton ();
     480          157 :   for (unsigned int i = 0; i<batch_size; i++)
     481              :   {
     482          151 :     TALER_planchet_setup_coin_priv (&ps[i],
     483              :                                     alg_values,
     484              :                                     &coin_priv[i]);
     485          151 :     TALER_planchet_blinding_secret_create (&ps[i],
     486              :                                            alg_values,
     487              :                                            &bks[i]);
     488              :   }
     489         2058 :   for (unsigned int k = 0; k<MAX_KEYS; k++)
     490              :   {
     491         2056 :     if (success && ! check_sigs)
     492            4 :       break; /* only do one round */
     493         2052 :     if (! keys[k].valid)
     494         2038 :       continue;
     495           14 :     if (GNUNET_CRYPTO_BSA_RSA !=
     496           14 :         keys[k].denom_pub.bsign_pub_key->cipher)
     497            0 :       continue;
     498           14 :     {
     499           14 :       struct TALER_PlanchetDetail pd[batch_size];
     500           14 :       struct TALER_CRYPTO_RsaSignRequest rsr[batch_size];
     501              : 
     502          429 :       for (unsigned int i = 0; i<batch_size; i++)
     503              :       {
     504          415 :         GNUNET_assert (GNUNET_YES ==
     505              :                        TALER_planchet_prepare (&keys[k].denom_pub,
     506              :                                                alg_values,
     507              :                                                &bks[i],
     508              :                                                NULL,
     509              :                                                &coin_priv[i],
     510              :                                                &ach[i],
     511              :                                                &c_hash[i],
     512              :                                                &pd[i]));
     513              :         rsr[i].h_rsa
     514          415 :           = &keys[k].h_rsa;
     515              :         rsr[i].msg
     516          415 :           = pd[i].blinded_planchet.blinded_message->details.rsa_blinded_message.
     517              :             blinded_msg;
     518              :         rsr[i].msg_size
     519          415 :           = pd[i].blinded_planchet.blinded_message->details.rsa_blinded_message.
     520              :             blinded_msg_size;
     521              :       }
     522           14 :       ec = TALER_CRYPTO_helper_rsa_batch_sign (dh,
     523              :                                                batch_size,
     524              :                                                rsr,
     525              :                                                ds);
     526          429 :       for (unsigned int i = 0; i<batch_size; i++)
     527              :       {
     528          415 :         if (TALER_EC_NONE == ec)
     529          151 :           GNUNET_break (GNUNET_CRYPTO_BSA_RSA ==
     530              :                         ds[i].blinded_sig->cipher);
     531          415 :         TALER_blinded_planchet_free (&pd[i].blinded_planchet);
     532              :       }
     533              :     }
     534           14 :     switch (ec)
     535              :     {
     536            6 :     case TALER_EC_NONE:
     537            6 :       if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_remaining (
     538              :                                       keys[k].start_time.abs_time),
     539              :                                     >,
     540              :                                     GNUNET_TIME_UNIT_SECONDS))
     541              :       {
     542              :         /* key worked too early */
     543            0 :         GNUNET_break (0);
     544            0 :         return 4;
     545              :       }
     546            6 :       if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_duration (
     547              :                                       keys[k].start_time.abs_time),
     548              :                                     >,
     549              :                                     keys[k].validity_duration))
     550              :       {
     551              :         /* key worked too later */
     552            0 :         GNUNET_break (0);
     553            0 :         return 5;
     554              :       }
     555          157 :       for (unsigned int i = 0; i<batch_size; i++)
     556              :       {
     557              :         struct TALER_DenominationSignature rs;
     558              : 
     559          151 :         if (check_sigs)
     560              :         {
     561           66 :           if (GNUNET_OK !=
     562           66 :               TALER_denom_sig_unblind (&rs,
     563           66 :                                        &ds[i],
     564           66 :                                        &bks[i],
     565           66 :                                        &c_hash[i],
     566              :                                        alg_values,
     567           66 :                                        &keys[k].denom_pub))
     568              :           {
     569            0 :             GNUNET_break (0);
     570            0 :             return 6;
     571              :           }
     572              :         }
     573          151 :         TALER_blinded_denom_sig_free (&ds[i]);
     574          151 :         if (check_sigs)
     575              :         {
     576           66 :           if (GNUNET_OK !=
     577           66 :               TALER_denom_pub_verify (&keys[k].denom_pub,
     578              :                                       &rs,
     579           66 :                                       &c_hash[i]))
     580              :           {
     581              :             /* signature invalid */
     582            0 :             GNUNET_break (0);
     583            0 :             TALER_denom_sig_free (&rs);
     584            0 :             return 7;
     585              :           }
     586           66 :           TALER_denom_sig_free (&rs);
     587              :         }
     588              :       }
     589            6 :       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     590              :                   "Received valid signature for key %s\n",
     591              :                   GNUNET_h2s (&keys[k].h_rsa.hash));
     592            6 :       success = true;
     593            6 :       break;
     594            8 :     case TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY:
     595              :       /* This 'failure' is expected, we're testing also for the
     596              :          error handling! */
     597          272 :       for (unsigned int i = 0; i<batch_size; i++)
     598          264 :         TALER_blinded_denom_sig_free (&ds[i]);
     599            8 :       if ( (GNUNET_TIME_relative_is_zero (
     600              :               GNUNET_TIME_absolute_get_remaining (
     601            0 :                 keys[k].start_time.abs_time))) &&
     602            0 :            (GNUNET_TIME_relative_cmp (
     603              :               GNUNET_TIME_absolute_get_duration (
     604              :                 keys[k].start_time.abs_time),
     605              :               <,
     606              :               keys[k].validity_duration)) )
     607              :       {
     608              :         /* key should have worked! */
     609            0 :         GNUNET_break (0);
     610            0 :         return 6;
     611              :       }
     612            8 :       break;
     613            0 :     case TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN:
     614            0 :       for (unsigned int i = 0; i<batch_size; i++)
     615            0 :         TALER_blinded_denom_sig_free (&ds[i]);
     616            0 :       break;
     617            0 :     default:
     618              :       /* unexpected error */
     619            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     620              :                   "Unexpected error %d at %s:%u\n",
     621              :                   ec,
     622              :                   __FILE__,
     623              :                   __LINE__);
     624            0 :       for (unsigned int i = 0; i<batch_size; i++)
     625            0 :         TALER_blinded_denom_sig_free (&ds[i]);
     626            0 :       return 7;
     627              :     }
     628              :   }
     629            6 :   if (! success)
     630              :   {
     631              :     /* no valid key for signing found, also bad */
     632            0 :     GNUNET_break (0);
     633            0 :     return 16;
     634              :   }
     635              : 
     636              :   /* check signing does not work if the key is unknown */
     637            6 :   if (check_sigs)
     638              :   {
     639              :     struct TALER_RsaPubHashP rnd;
     640            2 :     struct TALER_CRYPTO_RsaSignRequest rsr = {
     641              :       .h_rsa = &rnd,
     642              :       .msg = "Hello",
     643              :       .msg_size = strlen ("Hello")
     644              :     };
     645              : 
     646            2 :     GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
     647              :                                 &rnd,
     648              :                                 sizeof (rnd));
     649            2 :     ec = TALER_CRYPTO_helper_rsa_batch_sign (dh,
     650              :                                              1,
     651              :                                              &rsr,
     652              :                                              ds);
     653            2 :     if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec)
     654              :     {
     655            0 :       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     656              :                   "Signing with invalid key returned unexpected status %d\n",
     657              :                   ec);
     658            0 :       if (TALER_EC_NONE == ec)
     659            0 :         TALER_blinded_denom_sig_free (ds);
     660            0 :       GNUNET_break (0);
     661            0 :       return 17;
     662              :     }
     663            2 :     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     664              :                 "Signing with invalid key %s failed as desired\n",
     665              :                 GNUNET_h2s (&rnd.hash));
     666              :   }
     667            6 :   return 0;
     668              : }
     669              : 
     670              : 
     671              : /**
     672              :  * Benchmark signing logic.
     673              :  *
     674              :  * @param dh handle to the helper
     675              :  * @return 0 on success
     676              :  */
     677              : static int
     678            9 : perf_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh,
     679              :               const char *type)
     680              : {
     681              :   struct TALER_BlindedDenominationSignature ds;
     682              :   enum TALER_ErrorCode ec;
     683              :   struct GNUNET_TIME_Relative duration;
     684              :   struct TALER_PlanchetMasterSecretP ps;
     685              :   struct TALER_CoinSpendPrivateKeyP coin_priv;
     686              :   struct TALER_AgeCommitmentHashP ach;
     687              :   union GNUNET_CRYPTO_BlindingSecretP bks;
     688              :   const struct TALER_ExchangeBlindingValues *alg_values
     689            9 :     = TALER_denom_ewv_rsa_singleton ();
     690              : 
     691            9 :   TALER_planchet_master_setup_random (&ps);
     692            9 :   TALER_planchet_setup_coin_priv (&ps,
     693              :                                   alg_values,
     694              :                                   &coin_priv);
     695            9 :   TALER_planchet_blinding_secret_create (&ps,
     696              :                                          alg_values,
     697              :                                          &bks);
     698            9 :   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
     699              :                               &ach,
     700              :                               sizeof(ach));
     701            9 :   duration = GNUNET_TIME_UNIT_ZERO;
     702            9 :   TALER_CRYPTO_helper_rsa_poll (dh);
     703           18 :   for (unsigned int j = 0; j<NUM_SIGN_PERFS;)
     704              :   {
     705         9225 :     for (unsigned int i = 0; i<MAX_KEYS; i++)
     706              :     {
     707         9216 :       if (! keys[i].valid)
     708         9147 :         continue;
     709           69 :       if (GNUNET_CRYPTO_BSA_RSA !=
     710           69 :           keys[i].denom_pub.bsign_pub_key->cipher)
     711            0 :         continue;
     712           69 :       if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_remaining (
     713              :                                       keys[i].start_time.abs_time),
     714              :                                     >,
     715              :                                     GNUNET_TIME_UNIT_SECONDS))
     716           52 :         continue;
     717           17 :       if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_duration (
     718              :                                       keys[i].start_time.abs_time),
     719              :                                     >,
     720              :                                     keys[i].validity_duration))
     721            0 :         continue;
     722              :       {
     723              :         struct TALER_CoinPubHashP c_hash;
     724              :         struct TALER_PlanchetDetail pd;
     725              : 
     726           17 :         GNUNET_assert (GNUNET_YES ==
     727              :                        TALER_planchet_prepare (&keys[i].denom_pub,
     728              :                                                alg_values,
     729              :                                                &bks,
     730              :                                                NULL,
     731              :                                                &coin_priv,
     732              :                                                &ach,
     733              :                                                &c_hash,
     734              :                                                &pd));
     735              :         /* use this key as long as it works */
     736              :         while (1)
     737          891 :         {
     738          908 :           struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get ();
     739              :           struct GNUNET_TIME_Relative delay;
     740          908 :           struct TALER_CRYPTO_RsaSignRequest rsr = {
     741          908 :             .h_rsa = &keys[i].h_rsa,
     742              :             .msg =
     743          908 :               pd.blinded_planchet.blinded_message->details.rsa_blinded_message.
     744              :               blinded_msg,
     745              :             .msg_size =
     746          908 :               pd.blinded_planchet.blinded_message->details.rsa_blinded_message.
     747              :               blinded_msg_size
     748              :           };
     749              : 
     750          908 :           ec = TALER_CRYPTO_helper_rsa_batch_sign (dh,
     751              :                                                    1,
     752              :                                                    &rsr,
     753              :                                                    &ds);
     754          908 :           if (TALER_EC_NONE != ec)
     755            0 :             break;
     756          908 :           delay = GNUNET_TIME_absolute_get_duration (start);
     757          908 :           duration = GNUNET_TIME_relative_add (duration,
     758              :                                                delay);
     759          908 :           TALER_blinded_denom_sig_free (&ds);
     760          908 :           j++;
     761          908 :           if (NUM_SIGN_PERFS <= j)
     762           17 :             break;
     763              :         }
     764           17 :         TALER_blinded_planchet_free (&pd.blinded_planchet);
     765              :       }
     766              :     } /* for i */
     767              :   } /* for j */
     768            9 :   fprintf (stderr,
     769              :            "%u (%s) signature operations took %s\n",
     770              :            (unsigned int) NUM_SIGN_PERFS,
     771              :            type,
     772              :            GNUNET_STRINGS_relative_time_to_string (duration,
     773              :                                                    GNUNET_YES));
     774            9 :   return 0;
     775              : }
     776              : 
     777              : 
     778              : /**
     779              :  * Parallel signing logic.
     780              :  *
     781              :  * @param esh handle to the helper
     782              :  * @return 0 on success
     783              :  */
     784              : static int
     785            1 : par_signing (struct GNUNET_CONFIGURATION_Handle *cfg)
     786              : {
     787              :   struct GNUNET_TIME_Absolute start;
     788              :   struct GNUNET_TIME_Relative duration;
     789              :   pid_t pids[NUM_CORES];
     790              :   struct TALER_CRYPTO_RsaDenominationHelper *dh;
     791              : 
     792            1 :   start = GNUNET_TIME_absolute_get ();
     793            9 :   for (unsigned int i = 0; i<NUM_CORES; i++)
     794              :   {
     795            8 :     pids[i] = fork ();
     796           16 :     num_keys = 0;
     797           16 :     GNUNET_assert (-1 != pids[i]);
     798           16 :     if (0 == pids[i])
     799              :     {
     800              :       int ret;
     801              : 
     802            8 :       dh = TALER_CRYPTO_helper_rsa_connect (cfg,
     803              :                                             "taler-exchange",
     804              :                                             &key_cb,
     805              :                                             NULL);
     806            8 :       GNUNET_assert (NULL != dh);
     807            8 :       ret = perf_signing (dh,
     808              :                           "parallel");
     809            8 :       TALER_CRYPTO_helper_rsa_disconnect (dh);
     810            8 :       free_keys ();
     811            8 :       exit (ret);
     812              :     }
     813              :   }
     814            9 :   for (unsigned int i = 0; i<NUM_CORES; i++)
     815              :   {
     816              :     int wstatus;
     817              : 
     818            8 :     GNUNET_assert (pids[i] ==
     819              :                    waitpid (pids[i],
     820              :                             &wstatus,
     821              :                             0));
     822              :   }
     823            1 :   duration = GNUNET_TIME_absolute_get_duration (start);
     824            1 :   fprintf (stderr,
     825              :            "%u (parallel) signature operations took %s (total real time)\n",
     826              :            (unsigned int) NUM_SIGN_PERFS * NUM_CORES,
     827              :            GNUNET_STRINGS_relative_time_to_string (duration,
     828              :                                                    GNUNET_YES));
     829            1 :   return 0;
     830              : }
     831              : 
     832              : 
     833              : /**
     834              :  * Main entry point into the test logic with the helper already running.
     835              :  */
     836              : static int
     837            1 : run_test (void)
     838              : {
     839              :   struct GNUNET_CONFIGURATION_Handle *cfg;
     840              :   struct TALER_CRYPTO_RsaDenominationHelper *dh;
     841            1 :   struct timespec req = {
     842              :     .tv_nsec = 250000000
     843              :   };
     844              :   int ret;
     845              : 
     846            1 :   cfg = GNUNET_CONFIGURATION_create (TALER_EXCHANGE_project_data ());
     847            1 :   if (GNUNET_OK !=
     848            1 :       GNUNET_CONFIGURATION_load (cfg,
     849              :                                  "test_helper_rsa.conf"))
     850              :   {
     851            0 :     GNUNET_break (0);
     852            0 :     return 77;
     853              :   }
     854              : 
     855            1 :   fprintf (stderr,
     856              :            "Waiting for helper to start ... ");
     857            1 :   for (unsigned int i = 0; i<100; i++)
     858              :   {
     859            1 :     nanosleep (&req,
     860              :                NULL);
     861            1 :     dh = TALER_CRYPTO_helper_rsa_connect (cfg,
     862              :                                           "taler-exchange",
     863              :                                           &key_cb,
     864              :                                           NULL);
     865            1 :     if (NULL != dh)
     866            1 :       break;
     867            0 :     fprintf (stderr, ".");
     868              :   }
     869            1 :   if (NULL == dh)
     870              :   {
     871            0 :     fprintf (stderr,
     872              :              "\nFAILED: timeout trying to connect to helper\n");
     873            0 :     GNUNET_CONFIGURATION_destroy (cfg);
     874            0 :     return 1;
     875              :   }
     876            1 :   if (0 == num_keys)
     877              :   {
     878            0 :     fprintf (stderr,
     879              :              "\nFAILED: timeout trying to connect to helper\n");
     880            0 :     TALER_CRYPTO_helper_rsa_disconnect (dh);
     881            0 :     GNUNET_CONFIGURATION_destroy (cfg);
     882            0 :     return 1;
     883              :   }
     884            1 :   fprintf (stderr,
     885              :            " Done (%u keys)\n",
     886              :            num_keys);
     887            1 :   ret = 0;
     888            1 :   if (0 == ret)
     889            1 :     ret = test_revocation (dh);
     890            1 :   if (0 == ret)
     891            1 :     ret = test_signing (dh);
     892            1 :   if (0 == ret)
     893            1 :     ret = test_batch_signing (dh,
     894              :                               2,
     895              :                               true);
     896            1 :   if (0 == ret)
     897            1 :     ret = test_batch_signing (dh,
     898              :                               64,
     899              :                               true);
     900            5 :   for (unsigned int i = 0; i<4; i++)
     901              :   {
     902              :     static unsigned int batches[] = { 1, 4, 16, 64 };
     903            4 :     unsigned int batch_size = batches[i];
     904              :     struct GNUNET_TIME_Absolute start;
     905              :     struct GNUNET_TIME_Relative duration;
     906              : 
     907            4 :     start = GNUNET_TIME_absolute_get ();
     908            4 :     if (0 != ret)
     909            0 :       break;
     910            4 :     ret = test_batch_signing (dh,
     911              :                               batch_size,
     912              :                               false);
     913            4 :     duration = GNUNET_TIME_absolute_get_duration (start);
     914            4 :     fprintf (stderr,
     915              :              "%4u (batch) signature operations took %s (total real time)\n",
     916              :              (unsigned int) batch_size,
     917              :              GNUNET_STRINGS_relative_time_to_string (duration,
     918              :                                                      GNUNET_YES));
     919              :   }
     920            1 :   if (0 == ret)
     921            1 :     ret = perf_signing (dh,
     922              :                         "sequential");
     923            1 :   TALER_CRYPTO_helper_rsa_disconnect (dh);
     924            1 :   free_keys ();
     925            1 :   if (0 == ret)
     926            1 :     ret = par_signing (cfg);
     927              :   /* clean up our state */
     928            1 :   GNUNET_CONFIGURATION_destroy (cfg);
     929            1 :   return ret;
     930              : }
     931              : 
     932              : 
     933              : int
     934            1 : main (int argc,
     935              :       const char *const argv[])
     936              : {
     937            1 :   const char *loglevel = "WARNING";
     938              :   struct GNUNET_Process *helper;
     939              :   char *libexec_dir;
     940              :   char *binary_name;
     941              :   int ret;
     942              :   enum GNUNET_OS_ProcessStatusType type;
     943              :   unsigned long code;
     944              : 
     945              :   (void) argc;
     946              :   (void) argv;
     947            1 :   unsetenv ("XDG_DATA_HOME");
     948            1 :   unsetenv ("XDG_CONFIG_HOME");
     949            1 :   GNUNET_log_setup ("test-helper-rsa",
     950              :                     loglevel,
     951              :                     NULL);
     952            1 :   libexec_dir = GNUNET_OS_installation_get_path (TALER_EXCHANGE_project_data (),
     953              :                                                  GNUNET_OS_IPK_BINDIR);
     954            1 :   GNUNET_asprintf (&binary_name,
     955              :                    "%s/%s",
     956              :                    libexec_dir,
     957              :                    "taler-exchange-secmod-rsa");
     958            1 :   GNUNET_free (libexec_dir);
     959            1 :   helper = GNUNET_process_create (GNUNET_OS_INHERIT_STD_ERR);
     960            1 :   if (GNUNET_OK !=
     961            1 :       GNUNET_process_run_command_va (helper,
     962              :                                      binary_name,
     963              :                                      binary_name,
     964              :                                      "-c",
     965              :                                      "test_helper_rsa.conf",
     966              :                                      "-L",
     967              :                                      loglevel,
     968              :                                      NULL))
     969              :   {
     970            0 :     GNUNET_process_destroy (helper);
     971            0 :     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
     972              :                               "exec",
     973              :                               binary_name);
     974            0 :     GNUNET_free (binary_name);
     975            0 :     return 77;
     976              :   }
     977            1 :   GNUNET_free (binary_name);
     978            1 :   ret = run_test ();
     979              : 
     980            1 :   GNUNET_break (GNUNET_OK ==
     981              :                 GNUNET_process_kill (helper,
     982              :                                      SIGTERM));
     983            1 :   if (GNUNET_OK !=
     984            1 :       GNUNET_process_wait (helper,
     985              :                            true,
     986              :                            &type,
     987              :                            &code))
     988              :   {
     989            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     990              :                 "Helper process did not die voluntarily, killing hard\n");
     991            0 :     GNUNET_break (GNUNET_OK ==
     992              :                   GNUNET_process_kill (helper,
     993              :                                        SIGKILL));
     994            0 :     ret = 4;
     995              :   }
     996            1 :   else if ( (GNUNET_OS_PROCESS_EXITED != type) ||
     997            1 :             (0 != code) )
     998              :   {
     999            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    1000              :                 "Helper died with unexpected status %d/%d\n",
    1001              :                 (int) type,
    1002              :                 (int) code);
    1003            0 :     ret = 5;
    1004              :   }
    1005            1 :   GNUNET_process_destroy (helper);
    1006            1 :   return ret;
    1007              : }
    1008              : 
    1009              : 
    1010              : /* end of test_helper_rsa.c */
        

Generated by: LCOV version 2.0-1