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


      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 "taler/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_sign (dh,
    326                                            &rsr,
    327                                            &ds);
    328       }
    329       TALER_blinded_planchet_free (&pd.blinded_planchet);
    330     }
    331     switch (ec)
    332     {
    333     case TALER_EC_NONE:
    334       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         GNUNET_break (0);
    341         return 4;
    342       }
    343       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         GNUNET_break (0);
    350         return 5;
    351       }
    352       {
    353         struct TALER_DenominationSignature rs;
    354 
    355         if (GNUNET_OK !=
    356             TALER_denom_sig_unblind (&rs,
    357                                      &ds,
    358                                      &bks,
    359                                      &c_hash,
    360                                      alg_values,
    361                                      &keys[i].denom_pub))
    362         {
    363           GNUNET_break (0);
    364           return 6;
    365         }
    366         TALER_blinded_denom_sig_free (&ds);
    367         if (GNUNET_OK !=
    368             TALER_denom_pub_verify (&keys[i].denom_pub,
    369                                     &rs,
    370                                     &c_hash))
    371         {
    372           /* signature invalid */
    373           GNUNET_break (0);
    374           TALER_denom_sig_free (&rs);
    375           return 7;
    376         }
    377         TALER_denom_sig_free (&rs);
    378       }
    379       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    380                   "Received valid signature for key %s\n",
    381                   GNUNET_h2s (&keys[i].h_rsa.hash));
    382       success = true;
    383       break;
    384     case TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY:
    385       /* This 'failure' is expected, we're testing also for the
    386          error handling! */
    387       if ( (GNUNET_TIME_relative_is_zero (
    388               GNUNET_TIME_absolute_get_remaining (
    389                 keys[i].start_time.abs_time))) &&
    390            (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         GNUNET_break (0);
    398         return 6;
    399       }
    400       break;
    401     default:
    402       /* unexpected error */
    403       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    404                   "Unexpected error %d at %s:%u\n",
    405                   ec,
    406                   __FILE__,
    407                   __LINE__);
    408       return 7;
    409     }
    410   }
    411   if (! success)
    412   {
    413     /* no valid key for signing found, also bad */
    414     GNUNET_break (0);
    415     return 16;
    416   }
    417 
    418   /* check signing does not work if the key is unknown */
    419   {
    420     struct TALER_RsaPubHashP rnd;
    421     struct TALER_CRYPTO_RsaSignRequest rsr = {
    422       .h_rsa = &rnd,
    423       .msg = "Hello",
    424       .msg_size = strlen ("Hello")
    425     };
    426 
    427     GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
    428                                 &rnd,
    429                                 sizeof (rnd));
    430     ec = TALER_CRYPTO_helper_rsa_sign (dh,
    431                                        &rsr,
    432                                        &ds);
    433     if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec)
    434     {
    435       if (TALER_EC_NONE == ec)
    436         TALER_blinded_denom_sig_free (&ds);
    437       GNUNET_break (0);
    438       return 17;
    439     }
    440     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    441                 "Signing with invalid key %s failed as desired\n",
    442                 GNUNET_h2s (&rnd.hash));
    443   }
    444   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 test_batch_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh,
    458                     unsigned int batch_size,
    459                     bool check_sigs)
    460 {
    461   struct TALER_BlindedDenominationSignature ds[batch_size];
    462   enum TALER_ErrorCode ec;
    463   bool success = false;
    464   struct TALER_PlanchetMasterSecretP ps[batch_size];
    465   const struct TALER_ExchangeBlindingValues *alg_values;
    466   struct TALER_AgeCommitmentHashP ach[batch_size];
    467   struct TALER_CoinPubHashP c_hash[batch_size];
    468   struct TALER_CoinSpendPrivateKeyP coin_priv[batch_size];
    469   union GNUNET_CRYPTO_BlindingSecretP bks[batch_size];
    470 
    471   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
    472                               &ps,
    473                               sizeof (ps));
    474   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
    475                               &ach,
    476                               sizeof(ach));
    477   alg_values = TALER_denom_ewv_rsa_singleton ();
    478   for (unsigned int i = 0; i<batch_size; i++)
    479   {
    480     TALER_planchet_setup_coin_priv (&ps[i],
    481                                     alg_values,
    482                                     &coin_priv[i]);
    483     TALER_planchet_blinding_secret_create (&ps[i],
    484                                            alg_values,
    485                                            &bks[i]);
    486   }
    487   for (unsigned int k = 0; k<MAX_KEYS; k++)
    488   {
    489     if (success && ! check_sigs)
    490       break; /* only do one round */
    491     if (! keys[k].valid)
    492       continue;
    493     if (GNUNET_CRYPTO_BSA_RSA !=
    494         keys[k].denom_pub.bsign_pub_key->cipher)
    495       continue;
    496     {
    497       struct TALER_PlanchetDetail pd[batch_size];
    498       struct TALER_CRYPTO_RsaSignRequest rsr[batch_size];
    499 
    500       for (unsigned int i = 0; i<batch_size; i++)
    501       {
    502         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           = &keys[k].h_rsa;
    513         rsr[i].msg
    514           = pd[i].blinded_planchet.blinded_message->details.rsa_blinded_message.
    515             blinded_msg;
    516         rsr[i].msg_size
    517           = pd[i].blinded_planchet.blinded_message->details.rsa_blinded_message.
    518             blinded_msg_size;
    519       }
    520       ec = TALER_CRYPTO_helper_rsa_batch_sign (dh,
    521                                                batch_size,
    522                                                rsr,
    523                                                ds);
    524       for (unsigned int i = 0; i<batch_size; i++)
    525       {
    526         if (TALER_EC_NONE == ec)
    527           GNUNET_break (GNUNET_CRYPTO_BSA_RSA ==
    528                         ds[i].blinded_sig->cipher);
    529         TALER_blinded_planchet_free (&pd[i].blinded_planchet);
    530       }
    531     }
    532     switch (ec)
    533     {
    534     case TALER_EC_NONE:
    535       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         GNUNET_break (0);
    542         return 4;
    543       }
    544       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         GNUNET_break (0);
    551         return 5;
    552       }
    553       for (unsigned int i = 0; i<batch_size; i++)
    554       {
    555         struct TALER_DenominationSignature rs;
    556 
    557         if (check_sigs)
    558         {
    559           if (GNUNET_OK !=
    560               TALER_denom_sig_unblind (&rs,
    561                                        &ds[i],
    562                                        &bks[i],
    563                                        &c_hash[i],
    564                                        alg_values,
    565                                        &keys[k].denom_pub))
    566           {
    567             GNUNET_break (0);
    568             return 6;
    569           }
    570         }
    571         TALER_blinded_denom_sig_free (&ds[i]);
    572         if (check_sigs)
    573         {
    574           if (GNUNET_OK !=
    575               TALER_denom_pub_verify (&keys[k].denom_pub,
    576                                       &rs,
    577                                       &c_hash[i]))
    578           {
    579             /* signature invalid */
    580             GNUNET_break (0);
    581             TALER_denom_sig_free (&rs);
    582             return 7;
    583           }
    584           TALER_denom_sig_free (&rs);
    585         }
    586       }
    587       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    588                   "Received valid signature for key %s\n",
    589                   GNUNET_h2s (&keys[k].h_rsa.hash));
    590       success = true;
    591       break;
    592     case TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY:
    593       /* This 'failure' is expected, we're testing also for the
    594          error handling! */
    595       for (unsigned int i = 0; i<batch_size; i++)
    596         TALER_blinded_denom_sig_free (&ds[i]);
    597       if ( (GNUNET_TIME_relative_is_zero (
    598               GNUNET_TIME_absolute_get_remaining (
    599                 keys[k].start_time.abs_time))) &&
    600            (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         GNUNET_break (0);
    608         return 6;
    609       }
    610       break;
    611     case TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN:
    612       for (unsigned int i = 0; i<batch_size; i++)
    613         TALER_blinded_denom_sig_free (&ds[i]);
    614       break;
    615     default:
    616       /* unexpected error */
    617       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    618                   "Unexpected error %d at %s:%u\n",
    619                   ec,
    620                   __FILE__,
    621                   __LINE__);
    622       for (unsigned int i = 0; i<batch_size; i++)
    623         TALER_blinded_denom_sig_free (&ds[i]);
    624       return 7;
    625     }
    626   }
    627   if (! success)
    628   {
    629     /* no valid key for signing found, also bad */
    630     GNUNET_break (0);
    631     return 16;
    632   }
    633 
    634   /* check signing does not work if the key is unknown */
    635   if (check_sigs)
    636   {
    637     struct TALER_RsaPubHashP rnd;
    638     struct TALER_CRYPTO_RsaSignRequest rsr = {
    639       .h_rsa = &rnd,
    640       .msg = "Hello",
    641       .msg_size = strlen ("Hello")
    642     };
    643 
    644     GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
    645                                 &rnd,
    646                                 sizeof (rnd));
    647     ec = TALER_CRYPTO_helper_rsa_batch_sign (dh,
    648                                              1,
    649                                              &rsr,
    650                                              ds);
    651     if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec)
    652     {
    653       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    654                   "Signing with invalid key returned unexpected status %d\n",
    655                   ec);
    656       if (TALER_EC_NONE == ec)
    657         TALER_blinded_denom_sig_free (ds);
    658       GNUNET_break (0);
    659       return 17;
    660     }
    661     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    662                 "Signing with invalid key %s failed as desired\n",
    663                 GNUNET_h2s (&rnd.hash));
    664   }
    665   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 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_AgeCommitmentHashP ach;
    685   union GNUNET_CRYPTO_BlindingSecretP bks;
    686   const struct TALER_ExchangeBlindingValues *alg_values
    687     = TALER_denom_ewv_rsa_singleton ();
    688 
    689   TALER_planchet_master_setup_random (&ps);
    690   TALER_planchet_setup_coin_priv (&ps,
    691                                   alg_values,
    692                                   &coin_priv);
    693   TALER_planchet_blinding_secret_create (&ps,
    694                                          alg_values,
    695                                          &bks);
    696   GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
    697                               &ach,
    698                               sizeof(ach));
    699   duration = GNUNET_TIME_UNIT_ZERO;
    700   TALER_CRYPTO_helper_rsa_poll (dh);
    701   for (unsigned int j = 0; j<NUM_SIGN_PERFS;)
    702   {
    703     for (unsigned int i = 0; i<MAX_KEYS; i++)
    704     {
    705       if (! keys[i].valid)
    706         continue;
    707       if (GNUNET_CRYPTO_BSA_RSA !=
    708           keys[i].denom_pub.bsign_pub_key->cipher)
    709         continue;
    710       if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_remaining (
    711                                       keys[i].start_time.abs_time),
    712                                     >,
    713                                     GNUNET_TIME_UNIT_SECONDS))
    714         continue;
    715       if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_duration (
    716                                       keys[i].start_time.abs_time),
    717                                     >,
    718                                     keys[i].validity_duration))
    719         continue;
    720       {
    721         struct TALER_CoinPubHashP c_hash;
    722         struct TALER_PlanchetDetail pd;
    723 
    724         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         {
    736           struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get ();
    737           struct GNUNET_TIME_Relative delay;
    738           struct TALER_CRYPTO_RsaSignRequest rsr = {
    739             .h_rsa = &keys[i].h_rsa,
    740             .msg =
    741               pd.blinded_planchet.blinded_message->details.rsa_blinded_message.
    742               blinded_msg,
    743             .msg_size =
    744               pd.blinded_planchet.blinded_message->details.rsa_blinded_message.
    745               blinded_msg_size
    746           };
    747 
    748           ec = TALER_CRYPTO_helper_rsa_sign (dh,
    749                                              &rsr,
    750                                              &ds);
    751           if (TALER_EC_NONE != ec)
    752             break;
    753           delay = GNUNET_TIME_absolute_get_duration (start);
    754           duration = GNUNET_TIME_relative_add (duration,
    755                                                delay);
    756           TALER_blinded_denom_sig_free (&ds);
    757           j++;
    758           if (NUM_SIGN_PERFS <= j)
    759             break;
    760         }
    761         TALER_blinded_planchet_free (&pd.blinded_planchet);
    762       }
    763     } /* for i */
    764   } /* for j */
    765   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   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 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   start = GNUNET_TIME_absolute_get ();
    790   for (unsigned int i = 0; i<NUM_CORES; i++)
    791   {
    792     pids[i] = fork ();
    793     num_keys = 0;
    794     GNUNET_assert (-1 != pids[i]);
    795     if (0 == pids[i])
    796     {
    797       int ret;
    798 
    799       dh = TALER_CRYPTO_helper_rsa_connect (cfg,
    800                                             "taler-exchange",
    801                                             &key_cb,
    802                                             NULL);
    803       GNUNET_assert (NULL != dh);
    804       ret = perf_signing (dh,
    805                           "parallel");
    806       TALER_CRYPTO_helper_rsa_disconnect (dh);
    807       free_keys ();
    808       exit (ret);
    809     }
    810   }
    811   for (unsigned int i = 0; i<NUM_CORES; i++)
    812   {
    813     int wstatus;
    814 
    815     GNUNET_assert (pids[i] ==
    816                    waitpid (pids[i],
    817                             &wstatus,
    818                             0));
    819   }
    820   duration = GNUNET_TIME_absolute_get_duration (start);
    821   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   return 0;
    827 }
    828 
    829 
    830 /**
    831  * Main entry point into the test logic with the helper already running.
    832  */
    833 static int
    834 run_test (void)
    835 {
    836   struct GNUNET_CONFIGURATION_Handle *cfg;
    837   struct TALER_CRYPTO_RsaDenominationHelper *dh;
    838   struct timespec req = {
    839     .tv_nsec = 250000000
    840   };
    841   int ret;
    842 
    843   cfg = GNUNET_CONFIGURATION_create (TALER_EXCHANGE_project_data ());
    844   if (GNUNET_OK !=
    845       GNUNET_CONFIGURATION_load (cfg,
    846                                  "test_helper_rsa.conf"))
    847   {
    848     GNUNET_break (0);
    849     return 77;
    850   }
    851 
    852   fprintf (stderr,
    853            "Waiting for helper to start ... ");
    854   for (unsigned int i = 0; i<100; i++)
    855   {
    856     nanosleep (&req,
    857                NULL);
    858     dh = TALER_CRYPTO_helper_rsa_connect (cfg,
    859                                           "taler-exchange",
    860                                           &key_cb,
    861                                           NULL);
    862     if (NULL != dh)
    863       break;
    864     fprintf (stderr, ".");
    865   }
    866   if (NULL == dh)
    867   {
    868     fprintf (stderr,
    869              "\nFAILED: timeout trying to connect to helper\n");
    870     GNUNET_CONFIGURATION_destroy (cfg);
    871     return 1;
    872   }
    873   if (0 == num_keys)
    874   {
    875     fprintf (stderr,
    876              "\nFAILED: timeout trying to connect to helper\n");
    877     TALER_CRYPTO_helper_rsa_disconnect (dh);
    878     GNUNET_CONFIGURATION_destroy (cfg);
    879     return 1;
    880   }
    881   fprintf (stderr,
    882            " Done (%u keys)\n",
    883            num_keys);
    884   ret = 0;
    885   if (0 == ret)
    886     ret = test_revocation (dh);
    887   if (0 == ret)
    888     ret = test_signing (dh);
    889   if (0 == ret)
    890     ret = test_batch_signing (dh,
    891                               2,
    892                               true);
    893   if (0 == ret)
    894     ret = test_batch_signing (dh,
    895                               64,
    896                               true);
    897   for (unsigned int i = 0; i<4; i++)
    898   {
    899     static unsigned int batches[] = { 1, 4, 16, 64 };
    900     unsigned int batch_size = batches[i];
    901     struct GNUNET_TIME_Absolute start;
    902     struct GNUNET_TIME_Relative duration;
    903 
    904     start = GNUNET_TIME_absolute_get ();
    905     if (0 != ret)
    906       break;
    907     ret = test_batch_signing (dh,
    908                               batch_size,
    909                               false);
    910     duration = GNUNET_TIME_absolute_get_duration (start);
    911     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   if (0 == ret)
    918     ret = perf_signing (dh,
    919                         "sequential");
    920   TALER_CRYPTO_helper_rsa_disconnect (dh);
    921   free_keys ();
    922   if (0 == ret)
    923     ret = par_signing (cfg);
    924   /* clean up our state */
    925   GNUNET_CONFIGURATION_destroy (cfg);
    926   return ret;
    927 }
    928 
    929 
    930 int
    931 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   unsetenv ("XDG_DATA_HOME");
    944   unsetenv ("XDG_CONFIG_HOME");
    945   GNUNET_log_setup ("test-helper-rsa",
    946                     "WARNING",
    947                     NULL);
    948   libexec_dir = GNUNET_OS_installation_get_path (TALER_EXCHANGE_project_data (),
    949                                                  GNUNET_OS_IPK_BINDIR);
    950   GNUNET_asprintf (&binary_name,
    951                    "%s/%s",
    952                    libexec_dir,
    953                    "taler-exchange-secmod-rsa");
    954   GNUNET_free (libexec_dir);
    955   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   if (NULL == helper)
    965   {
    966     GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
    967                               "exec",
    968                               binary_name);
    969     GNUNET_free (binary_name);
    970     return 77;
    971   }
    972   GNUNET_free (binary_name);
    973   ret = run_test ();
    974 
    975   GNUNET_OS_process_kill (helper,
    976                           SIGTERM);
    977   if (GNUNET_OK !=
    978       GNUNET_OS_process_wait_status (helper,
    979                                      &type,
    980                                      &code))
    981   {
    982     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
    983                 "Helper process did not die voluntarily, killing hard\n");
    984     GNUNET_OS_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_OS_process_destroy (helper);
    998   return ret;
    999 }
   1000 
   1001 
   1002 /* end of test_helper_rsa.c */