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 (31371B)


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