diff options
| author | Christian Grothoff <christian@grothoff.org> | 2022-11-13 21:45:43 +0100 | 
|---|---|---|
| committer | Christian Grothoff <christian@grothoff.org> | 2022-11-13 21:45:43 +0100 | 
| commit | 231cdaf4f777165c3858d737f0b7b799d39758ce (patch) | |
| tree | d3e7cb8659b5dd3f7d52fbff548368e62f3ce34f /src | |
| parent | 390d241019c0c2695bae1532bf857e1c278d7747 (diff) | |
add test for batch CS derive/sign logic
Diffstat (limited to 'src')
| -rw-r--r-- | src/util/taler-exchange-secmod-cs.c | 78 | ||||
| -rw-r--r-- | src/util/taler-exchange-secmod-rsa.c | 3 | ||||
| -rw-r--r-- | src/util/test_helper_cs.c | 238 | 
3 files changed, 290 insertions, 29 deletions
| diff --git a/src/util/taler-exchange-secmod-cs.c b/src/util/taler-exchange-secmod-cs.c index 13148a16..231a8cd8 100644 --- a/src/util/taler-exchange-secmod-cs.c +++ b/src/util/taler-exchange-secmod-cs.c @@ -513,6 +513,28 @@ fail_sign (struct TES_Client *client,  /** + * Generate error response that deriving failed. + * + * @param client client to send response to + * @param ec error code to include + * @return #GNUNET_OK on success + */ +static enum GNUNET_GenericReturnValue +fail_derive (struct TES_Client *client, +             enum TALER_ErrorCode ec) +{ +  struct TALER_CRYPTO_RDeriveFailure sf = { +    .header.size = htons (sizeof (sf)), +    .header.type = htons (TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE), +    .ec = htonl (ec) +  }; + +  return TES_transmit (client->csock, +                       &sf.header); +} + + +/**   * Generate signature response.   *   * @param client client to send response to @@ -842,19 +864,25 @@ finish_job (struct TES_Client *client,  {    sem_down (&bj->sem);    sem_done (&bj->sem); -  if (TALER_EC_NONE != bj->ec) -  { -    fail_sign (client, -               bj->ec); -    return; -  }    switch (bj->type)    {    case TYPE_SIGN: +    if (TALER_EC_NONE != bj->ec) +    { +      fail_sign (client, +                 bj->ec); +      return; +    }      send_signature (client,                      &bj->details.sign.cs_answer);      break;    case TYPE_RDERIVE: +    if (TALER_EC_NONE != bj->ec) +    { +      fail_derive (client, +                   bj->ec); +      return; +    }      send_derivation (client,                       &bj->details.rderive.rpairp);      break; @@ -878,16 +906,19 @@ handle_batch_sign_request (struct TES_Client *client,    uint16_t size = ntohs (bsr->header.size) - sizeof (*bsr);    const void *off = (const void *) &bsr[1];    unsigned int idx = 0; -  struct BatchJob jobs[bs]; +  struct BatchJob jobs[GNUNET_NZL (bs)];    bool failure = false; +  GNUNET_log (GNUNET_ERROR_TYPE_INFO, +              "Handling batch sign request of size %u\n", +              (unsigned int) bs);    if (bs > TALER_MAX_FRESH_COINS)    {      GNUNET_break_op (0);      return GNUNET_SYSERR;    }    while ( (bs > 0) && -          (size > sizeof (struct TALER_CRYPTO_CsSignRequestMessage)) ) +          (size >= sizeof (struct TALER_CRYPTO_CsSignRequestMessage)) )    {      const struct TALER_CRYPTO_CsSignRequestMessage *sr = off;      uint16_t s = ntohs (sr->header.size); @@ -903,6 +934,9 @@ handle_batch_sign_request (struct TES_Client *client,      off += s;      size -= s;    } +  GNUNET_break_op (0 == size); +  bs = GNUNET_MIN (bs, +                   idx);    for (unsigned int i = 0; i<bs; i++)      finish_job (client,                  &jobs[i]); @@ -941,13 +975,16 @@ handle_batch_derive_request (struct TES_Client *client,    struct BatchJob jobs[bs];    bool failure = false; +  GNUNET_log (GNUNET_ERROR_TYPE_INFO, +              "Handling batch derivation request of size %u\n", +              (unsigned int) bs);    if (bs > TALER_MAX_FRESH_COINS)    {      GNUNET_break_op (0);      return GNUNET_SYSERR;    }    while ( (bs > 0) && -          (size > sizeof (struct TALER_CRYPTO_CsRDeriveRequest)) ) +          (size >= sizeof (struct TALER_CRYPTO_CsRDeriveRequest)) )    {      const struct TALER_CRYPTO_CsRDeriveRequest *rdr = off;      uint16_t s = ntohs (rdr->header.size); @@ -964,20 +1001,17 @@ handle_batch_derive_request (struct TES_Client *client,      off += s;      size -= s;    } +  GNUNET_break_op (0 == size); +  bs = GNUNET_MIN (bs, +                   idx);    for (unsigned int i = 0; i<bs; i++)      finish_job (client,                  &jobs[i]);    if (failure)    { -    struct TALER_CRYPTO_SignFailure sf = { -      .header.size = htons (sizeof (sf)), -      .header.type = htons (TALER_HELPER_CS_MT_RES_BATCH_RDERIVE_FAILURE), -      .ec = htonl (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE) -    }; -      GNUNET_break (0); -    return TES_transmit (client->csock, -                         &sf.header); +    return fail_derive (client, +                        TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE);    }    return GNUNET_OK;  } @@ -1219,14 +1253,8 @@ handle_r_derive_request (struct TES_Client *client,                    &r_pub);    if (TALER_EC_NONE != ec)    { -    struct TALER_CRYPTO_RDeriveFailure rdf = { -      .header.size = htons (sizeof (rdf)), -      .header.type = htons (TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE), -      .ec = htonl (ec) -    }; - -    return TES_transmit (client->csock, -                         &rdf.header); +    return fail_derive (client, +                        ec);    }    ret = send_derivation (client, diff --git a/src/util/taler-exchange-secmod-rsa.c b/src/util/taler-exchange-secmod-rsa.c index 779e1252..d5106c8a 100644 --- a/src/util/taler-exchange-secmod-rsa.c +++ b/src/util/taler-exchange-secmod-rsa.c @@ -766,6 +766,9 @@ handle_batch_sign_request (struct TES_Client *client,      off += s;      size -= s;    } +  GNUNET_break_op (0 == size); +  bs = GNUNET_MIN (bs, +                   idx);    for (unsigned int i = 0; i<bs; i++)      finish_job (client,                  &jobs[i]); diff --git a/src/util/test_helper_cs.c b/src/util/test_helper_cs.c index 7c57d50c..fdfc5c36 100644 --- a/src/util/test_helper_cs.c +++ b/src/util/test_helper_cs.c @@ -439,8 +439,6 @@ test_signing (struct TALER_CRYPTO_CsDenominationHelper *dh)        };        pd.blinded_planchet.cipher = TALER_DENOMINATION_CS; -      // keys[i].denom_pub.cipher = TALER_DENOMINATION_CS; -        TALER_cs_withdraw_nonce_derive (&ps,                                        &pd.blinded_planchet.details.                                        cs_blinded_planchet.nonce); @@ -593,6 +591,209 @@ test_signing (struct TALER_CRYPTO_CsDenominationHelper *dh)  /** + * Test batch signing logic. + * + * @param dh handle to the helper + * @param batch_size how large should the batch be + * @param check_sigs also check unknown key and signatures + * @return 0 on success + */ +static int +test_batch_signing (struct TALER_CRYPTO_CsDenominationHelper *dh, +                    unsigned int batch_size, +                    bool check_sigs) +{ +  struct TALER_BlindedDenominationSignature ds[batch_size]; +  enum TALER_ErrorCode ec; +  bool success = false; +  struct TALER_PlanchetMasterSecretP ps[batch_size]; +  struct TALER_CoinSpendPrivateKeyP coin_priv[batch_size]; +  union TALER_DenominationBlindingKeyP bks[batch_size]; +  struct TALER_CoinPubHashP c_hash[batch_size]; +  struct TALER_ExchangeWithdrawValues alg_values[batch_size]; + +  for (unsigned int i = 0; i<batch_size; i++) +    TALER_planchet_master_setup_random (&ps[i]); +  for (unsigned int k = 0; k<MAX_KEYS; k++) +  { +    if (! keys[k].valid) +      continue; +    { +      struct TALER_PlanchetDetail pd[batch_size]; +      struct TALER_CRYPTO_CsSignRequest csr[batch_size]; +      struct TALER_CRYPTO_CsDeriveRequest cdr[batch_size]; +      struct TALER_DenominationCSPublicRPairP crps[batch_size]; + +      for (unsigned int i = 0; i<batch_size; i++) +      { +        cdr[i].h_cs = &keys[k].h_cs; +        cdr[i].nonce = +          &pd[i].blinded_planchet.details.cs_blinded_planchet.nonce; +        pd[i].blinded_planchet.cipher = TALER_DENOMINATION_CS; +        TALER_cs_withdraw_nonce_derive ( +          &ps[i], +          &pd[i].blinded_planchet.details.cs_blinded_planchet.nonce); +        alg_values[i].cipher = TALER_DENOMINATION_CS; +      } +      ec = TALER_CRYPTO_helper_cs_r_batch_derive_withdraw ( +        dh, +        cdr, +        batch_size, +        crps); +      if (TALER_EC_NONE != ec) +        continue; +      for (unsigned int i = 0; i<batch_size; i++) +      { +        alg_values[i].details.cs_values = crps[i]; +        TALER_planchet_setup_coin_priv (&ps[i], +                                        &alg_values[i], +                                        &coin_priv[i]); +        TALER_planchet_blinding_secret_create (&ps[i], +                                               &alg_values[i], +                                               &bks[i]); +        GNUNET_assert (GNUNET_YES == +                       TALER_planchet_prepare (&keys[k].denom_pub, +                                               &alg_values[i], +                                               &bks[i], +                                               &coin_priv[i], +                                               NULL, /* no age commitment */ +                                               &c_hash[i], +                                               &pd[i])); +        GNUNET_log (GNUNET_ERROR_TYPE_INFO, +                    "Requesting signature with key %s\n", +                    GNUNET_h2s (&keys[k].h_cs.hash)); +        csr[i].h_cs = &keys[k].h_cs; +        csr[i].blinded_planchet +          = &pd[i].blinded_planchet.details.cs_blinded_planchet; +      } +      ec = TALER_CRYPTO_helper_cs_batch_sign_withdraw ( +        dh, +        csr, +        batch_size, +        ds); +    } +    switch (ec) +    { +    case TALER_EC_NONE: +      if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_remaining ( +                                      keys[k].start_time.abs_time), +                                    >, +                                    GNUNET_TIME_UNIT_SECONDS)) +      { +        /* key worked too early */ +        GNUNET_break (0); +        return 4; +      } +      if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_duration ( +                                      keys[k].start_time.abs_time), +                                    >, +                                    keys[k].validity_duration)) +      { +        /* key worked too later */ +        GNUNET_break (0); +        return 5; +      } +      if (check_sigs) +      { +        for (unsigned int i = 0; i<batch_size; i++) +        { +          struct TALER_FreshCoin coin; + +          if (GNUNET_OK != +              TALER_planchet_to_coin (&keys[k].denom_pub, +                                      &ds[i], +                                      &bks[i], +                                      &coin_priv[i], +                                      NULL, /* no age commitment */ +                                      &c_hash[i], +                                      &alg_values[i], +                                      &coin)) +          { +            GNUNET_break (0); +            return 6; +          } +        } +        GNUNET_log (GNUNET_ERROR_TYPE_INFO, +                    "Received valid signature for key %s\n", +                    GNUNET_h2s (&keys[k].h_cs.hash)); +      } +      success = true; +      break; +    case TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY: +      /* This 'failure' is expected, we're testing also for the +         error handling! */ +      if ( (GNUNET_TIME_relative_is_zero ( +              GNUNET_TIME_absolute_get_remaining ( +                keys[k].start_time.abs_time))) && +           (GNUNET_TIME_relative_cmp ( +              GNUNET_TIME_absolute_get_duration ( +                keys[k].start_time.abs_time), +              <, +              keys[k].validity_duration)) ) +      { +        /* key should have worked! */ +        GNUNET_break (0); +        return 6; +      } +      break; +    default: +      /* unexpected error */ +      GNUNET_log (GNUNET_ERROR_TYPE_ERROR, +                  "Unexpected error %d\n", +                  ec); +      return 7; +    } +  } +  if (! success) +  { +    /* no valid key for signing found, also bad */ +    GNUNET_break (0); +    return 16; +  } + +  /* check signing does not work if the key is unknown */ +  if (check_sigs) +  { +    struct TALER_PlanchetDetail pd; +    struct TALER_CsPubHashP rnd; +    struct TALER_CRYPTO_CsSignRequest csr; + +    GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, +                                &rnd, +                                sizeof (rnd)); +    pd.blinded_planchet.cipher = TALER_DENOMINATION_CS; +    GNUNET_assert (GNUNET_YES == +                   TALER_planchet_prepare (&keys[0].denom_pub, +                                           &alg_values[0], +                                           &bks[0], +                                           &coin_priv[0], +                                           NULL, /* no age commitment */ +                                           &c_hash[0], +                                           &pd)); +    csr.h_cs = &rnd; +    csr.blinded_planchet +      = &pd.blinded_planchet.details.cs_blinded_planchet; +    ec = TALER_CRYPTO_helper_cs_batch_sign_withdraw ( +      dh, +      &csr, +      1, +      &ds[0]); +    if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec) +    { +      if (TALER_EC_NONE == ec) +        TALER_blinded_denom_sig_free (ds); +      GNUNET_break (0); +      return 17; +    } +    GNUNET_log (GNUNET_ERROR_TYPE_INFO, +                "Signing with invalid key %s failed as desired\n", +                GNUNET_h2s (&rnd.hash)); +  } +  return 0; +} + + +/**   * Benchmark signing logic.   *   * @param dh handle to the helper @@ -813,6 +1014,34 @@ run_test (void)    if (0 == ret)      ret = test_signing (dh);    if (0 == ret) +    ret = test_batch_signing (dh, +                              2, +                              true); +  if (0 == ret) +    ret = test_batch_signing (dh, +                              256, +                              true); +  for (unsigned int i = 0; i<5; i++) +  { +    static unsigned int batches[] = { 1, 4, 16, 64, 256 }; +    unsigned int batch_size = batches[i]; +    struct GNUNET_TIME_Absolute start; +    struct GNUNET_TIME_Relative duration; + +    start = GNUNET_TIME_absolute_get (); +    if (0 != ret) +      break; +    ret = test_batch_signing (dh, +                              batch_size, +                              false); +    duration = GNUNET_TIME_absolute_get_duration (start); +    fprintf (stderr, +             "%4u (batch) signature operations took %s (total real time)\n", +             (unsigned int) batch_size, +             GNUNET_STRINGS_relative_time_to_string (duration, +                                                     GNUNET_YES)); +  } +  if (0 == ret)      ret = perf_signing (dh,                          "sequential");    TALER_CRYPTO_helper_cs_disconnect (dh); @@ -835,13 +1064,14 @@ main (int argc,    int ret;    enum GNUNET_OS_ProcessStatusType type;    unsigned long code; +  const char *loglev = "WARNING";    (void) argc;    (void) argv;    unsetenv ("XDG_DATA_HOME");    unsetenv ("XDG_CONFIG_HOME");    GNUNET_log_setup ("test-helper-cs", -                    "WARNING", +                    loglev,                      NULL);    GNUNET_OS_init (TALER_project_data_default ());    libexec_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_BINDIR); @@ -857,7 +1087,7 @@ main (int argc,                                      "-c",                                      "test_helper_cs.conf",                                      "-L", -                                    "WARNING", +                                    loglev,                                      NULL);    if (NULL == helper)    { | 
