aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2022-11-13 21:45:43 +0100
committerChristian Grothoff <christian@grothoff.org>2022-11-13 21:45:43 +0100
commit231cdaf4f777165c3858d737f0b7b799d39758ce (patch)
treed3e7cb8659b5dd3f7d52fbff548368e62f3ce34f /src/util
parent390d241019c0c2695bae1532bf857e1c278d7747 (diff)
add test for batch CS derive/sign logic
Diffstat (limited to 'src/util')
-rw-r--r--src/util/taler-exchange-secmod-cs.c78
-rw-r--r--src/util/taler-exchange-secmod-rsa.c3
-rw-r--r--src/util/test_helper_cs.c238
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 13148a16c..231a8cd87 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 779e12521..d5106c8a9 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 7c57d50cf..fdfc5c362 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)
{