exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

test_helper_rsa.c (30893B)


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