LCOV - code coverage report
Current view: top level - util - test_helper_rsa.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 281 362 77.6 %
Date: 2025-06-05 21:03:14 Functions: 9 9 100.0 %

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

Generated by: LCOV version 1.16