summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2022-11-13 14:46:43 +0100
committerChristian Grothoff <christian@grothoff.org>2022-11-13 14:46:43 +0100
commitb93b9dd074cf347c978b7c58c3ce71d55aa669fd (patch)
tree4261b57347aaa5ef0bfaf44eec690b891ce50460
parentf2eba7b8b7d1200ca653b2da17fefb4cdd7b432c (diff)
downloadexchange-b93b9dd074cf347c978b7c58c3ce71d55aa669fd.tar.gz
exchange-b93b9dd074cf347c978b7c58c3ce71d55aa669fd.tar.bz2
exchange-b93b9dd074cf347c978b7c58c3ce71d55aa669fd.zip
add support for batch signing in RSA
-rw-r--r--src/util/crypto_helper_rsa.c304
-rw-r--r--src/util/test_helper_rsa.c250
2 files changed, 405 insertions, 149 deletions
diff --git a/src/util/crypto_helper_rsa.c b/src/util/crypto_helper_rsa.c
index 811e5a036..58cc29a8f 100644
--- a/src/util/crypto_helper_rsa.c
+++ b/src/util/crypto_helper_rsa.c
@@ -623,6 +623,7 @@ TALER_CRYPTO_helper_rsa_batch_sign (
rsrs_length);
rpos = 0;
rend = 0;
+ wpos = 0;
while (rpos < rsrs_length)
{
unsigned int mlen = sizeof (struct TALER_CRYPTO_BatchSignRequest);
@@ -639,15 +640,15 @@ TALER_CRYPTO_helper_rsa_batch_sign (
char obuf[mlen] GNUNET_ALIGN;
struct TALER_CRYPTO_BatchSignRequest *bsr
= (struct TALER_CRYPTO_BatchSignRequest *) obuf;
- void *wpos;
+ void *wbuf;
bsr->header.type = htons (TALER_HELPER_RSA_MT_REQ_BATCH_SIGN);
bsr->header.size = htons (mlen);
bsr->batch_size = htonl (rend - rpos);
- wpos = &bsr[1];
+ wbuf = &bsr[1];
for (unsigned int i = rpos; i<rend; i++)
{
- struct TALER_CRYPTO_SignRequest *sr = wpos;
+ struct TALER_CRYPTO_SignRequest *sr = wbuf;
const struct TALER_CRYPTO_RsaSignRequest *rsr = &rsrs[i];
sr->header.type = htons (TALER_HELPER_RSA_MT_REQ_SIGN);
@@ -657,9 +658,13 @@ TALER_CRYPTO_helper_rsa_batch_sign (
memcpy (&sr[1],
rsr->msg,
rsr->msg_size);
- wpos += sizeof (*sr) + rsr->msg_size;
+ wbuf += sizeof (*sr) + rsr->msg_size;
}
- GNUNET_assert (wpos == &obuf[mlen]);
+ GNUNET_assert (wbuf == &obuf[mlen]);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending batch request [%u-%u)\n",
+ rpos,
+ rend);
if (GNUNET_OK !=
TALER_crypto_helper_send_all (dh->sock,
obuf,
@@ -672,170 +677,175 @@ TALER_CRYPTO_helper_rsa_batch_sign (
}
}
rpos = rend;
- }
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Awaiting reply\n");
- wpos = 0;
- {
- char buf[UINT16_MAX];
- size_t off = 0;
- const struct GNUNET_MessageHeader *hdr
- = (const struct GNUNET_MessageHeader *) buf;
- bool finished = false;
-
- while (1)
{
- uint16_t msize;
- ssize_t ret;
+ char buf[UINT16_MAX];
+ size_t off = 0;
+ const struct GNUNET_MessageHeader *hdr
+ = (const struct GNUNET_MessageHeader *) buf;
+ bool finished = false;
- ret = recv (dh->sock,
- &buf[off],
- sizeof (buf) - off,
- (finished && (0 == off))
+ while (1)
+ {
+ uint16_t msize;
+ ssize_t ret;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Awaiting reply at %u (up to %u)\n",
+ wpos,
+ rend);
+ ret = recv (dh->sock,
+ &buf[off],
+ sizeof (buf) - off,
+ (finished && (0 == off))
? MSG_DONTWAIT
: 0);
- if (ret < 0)
- {
- if (EINTR == errno)
- continue;
- if (EAGAIN == errno)
- {
- GNUNET_assert (finished);
- GNUNET_assert (0 == off);
- return ec;
- }
- GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
- "recv");
- do_disconnect (dh);
- ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
- break;
- }
- if (0 == ret)
- {
- GNUNET_break (0 == off);
- if (! finished)
- ec = TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
- return ec;
- }
- off += ret;
-more:
- if (off < sizeof (struct GNUNET_MessageHeader))
- continue;
- msize = ntohs (hdr->size);
- if (off < msize)
- continue;
- switch (ntohs (hdr->type))
- {
- case TALER_HELPER_RSA_MT_RES_SIGNATURE:
- if (msize < sizeof (struct TALER_CRYPTO_SignResponse))
+ if (ret < 0)
{
- GNUNET_break_op (0);
+ if (EINTR == errno)
+ continue;
+ if (EAGAIN == errno)
+ {
+ GNUNET_assert (finished);
+ GNUNET_assert (0 == off);
+ break;
+ }
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
+ "recv");
do_disconnect (dh);
- ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
- goto end;
+ ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
+ break;
}
- if (finished)
+ if (0 == ret)
{
- GNUNET_break_op (0);
- do_disconnect (dh);
- ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
- goto end;
+ GNUNET_break (0 == off);
+ if (! finished)
+ ec = TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
+ if (TALER_EC_NONE == ec)
+ break;
+ return ec;
}
+ off += ret;
+more:
+ if (off < sizeof (struct GNUNET_MessageHeader))
+ continue;
+ msize = ntohs (hdr->size);
+ if (off < msize)
+ continue;
+ switch (ntohs (hdr->type))
{
- const struct TALER_CRYPTO_SignResponse *sr =
- (const struct TALER_CRYPTO_SignResponse *) buf;
- struct GNUNET_CRYPTO_RsaSignature *rsa_signature;
-
- rsa_signature = GNUNET_CRYPTO_rsa_signature_decode (
- &sr[1],
- msize - sizeof (*sr));
- if (NULL == rsa_signature)
+ case TALER_HELPER_RSA_MT_RES_SIGNATURE:
+ if (msize < sizeof (struct TALER_CRYPTO_SignResponse))
{
GNUNET_break_op (0);
do_disconnect (dh);
- ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
- goto end;
+ return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+ }
+ if (finished)
+ {
+ GNUNET_break_op (0);
+ do_disconnect (dh);
+ return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+ }
+ {
+ const struct TALER_CRYPTO_SignResponse *sr =
+ (const struct TALER_CRYPTO_SignResponse *) buf;
+ struct GNUNET_CRYPTO_RsaSignature *rsa_signature;
+
+ rsa_signature = GNUNET_CRYPTO_rsa_signature_decode (
+ &sr[1],
+ msize - sizeof (*sr));
+ if (NULL == rsa_signature)
+ {
+ GNUNET_break_op (0);
+ do_disconnect (dh);
+ return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received %u signature\n",
+ wpos);
+ bss[wpos].cipher = TALER_DENOMINATION_RSA;
+ bss[wpos].details.blinded_rsa_signature = rsa_signature;
+ wpos++;
+ if (wpos == rend)
+ {
+ if (TALER_EC_INVALID == ec)
+ ec = TALER_EC_NONE;
+ finished = true;
+ }
+ break;
+ }
+ case TALER_HELPER_RSA_MT_RES_SIGN_FAILURE:
+ if (msize != sizeof (struct TALER_CRYPTO_SignFailure))
+ {
+ GNUNET_break_op (0);
+ do_disconnect (dh);
+ return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+ }
+ {
+ const struct TALER_CRYPTO_SignFailure *sf =
+ (const struct TALER_CRYPTO_SignFailure *) buf;
+
+ ec = (enum TALER_ErrorCode) ntohl (sf->ec);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Signing failed with status %d!\n",
+ ec);
+ wpos++;
+ if (wpos == rend)
+ {
+ finished = true;
+ }
+ break;
}
+ case TALER_HELPER_RSA_MT_AVAIL:
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received %u signature\n",
- wpos);
- bss[wpos].cipher = TALER_DENOMINATION_RSA;
- bss[wpos].details.blinded_rsa_signature = rsa_signature;
- wpos++;
- if (wpos == rsrs_length)
+ "Received new key!\n");
+ if (GNUNET_OK !=
+ handle_mt_avail (dh,
+ hdr))
{
- ec = TALER_EC_NONE;
- finished = true;
+ GNUNET_break_op (0);
+ do_disconnect (dh);
+ return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
}
- break;
- }
- case TALER_HELPER_RSA_MT_RES_SIGN_FAILURE:
- if (msize != sizeof (struct TALER_CRYPTO_SignFailure))
- {
- GNUNET_break_op (0);
- do_disconnect (dh);
- ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
- goto end;
- }
- {
- const struct TALER_CRYPTO_SignFailure *sf =
- (const struct TALER_CRYPTO_SignFailure *) buf;
-
- ec = (enum TALER_ErrorCode) ntohl (sf->ec);
+ break; /* while(1) loop ensures we recvfrom() again */
+ case TALER_HELPER_RSA_MT_PURGE:
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Signing failed!\n");
- finished = true;
+ "Received revocation!\n");
+ if (GNUNET_OK !=
+ handle_mt_purge (dh,
+ hdr))
+ {
+ GNUNET_break_op (0);
+ do_disconnect (dh);
+ return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
+ }
+ break; /* while(1) loop ensures we recvfrom() again */
+ case TALER_HELPER_RSA_SYNCED:
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Synchronized add odd time with RSA helper!\n");
+ dh->synced = true;
break;
- }
- case TALER_HELPER_RSA_MT_AVAIL:
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received new key!\n");
- if (GNUNET_OK !=
- handle_mt_avail (dh,
- hdr))
- {
+ default:
GNUNET_break_op (0);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Received unexpected message of type %u\n",
+ ntohs (hdr->type));
do_disconnect (dh);
- ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
- goto end;
+ return TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
}
- break; /* while(1) loop ensures we recvfrom() again */
- case TALER_HELPER_RSA_MT_PURGE:
- GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
- "Received revocation!\n");
- if (GNUNET_OK !=
- handle_mt_purge (dh,
- hdr))
- {
- GNUNET_break_op (0);
- do_disconnect (dh);
- ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
- goto end;
- }
- break; /* while(1) loop ensures we recvfrom() again */
- case TALER_HELPER_RSA_SYNCED:
- GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
- "Synchronized add odd time with RSA helper!\n");
- dh->synced = true;
- break;
- default:
- GNUNET_break_op (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Received unexpected message of type %u\n",
- ntohs (hdr->type));
- do_disconnect (dh);
- ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
- goto end;
- }
- memmove (buf,
- &buf[msize],
- off - msize);
- off -= msize;
- goto more;
- } /* while(1) */
-end:
- return ec;
- }
+ memmove (buf,
+ &buf[msize],
+ off - msize);
+ off -= msize;
+ goto more;
+ } /* while(1) */
+ } /* scope */
+ } /* while (rpos < rsrs_length) */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Existing with %u signatures and status %d\n",
+ wpos,
+ ec);
+ return ec;
}
diff --git a/src/util/test_helper_rsa.c b/src/util/test_helper_rsa.c
index 3f3eafddb..1b67607ce 100644
--- a/src/util/test_helper_rsa.c
+++ b/src/util/test_helper_rsa.c
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- (C) 2020, 2021 Taler Systems SA
+ (C) 2020, 2021, 2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -441,6 +441,223 @@ test_signing (struct TALER_CRYPTO_RsaDenominationHelper *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_RsaDenominationHelper *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_ExchangeWithdrawValues alg_values[batch_size];
+ struct TALER_AgeCommitmentHash ach[batch_size];
+ struct TALER_CoinPubHashP c_hash[batch_size];
+ struct TALER_CoinSpendPrivateKeyP coin_priv[batch_size];
+ union TALER_DenominationBlindingKeyP bks[batch_size];
+
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
+ &ps,
+ sizeof (ps));
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
+ &ach,
+ sizeof(ach));
+ for (unsigned int i = 0; i<batch_size; i++)
+ {
+ alg_values[i].cipher = TALER_DENOMINATION_RSA;
+ 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]);
+ }
+ for (unsigned int k = 0; k<MAX_KEYS; k++)
+ {
+ if (success && ! check_sigs)
+ break; /* only do one round */
+ if (! keys[k].valid)
+ continue;
+ if (TALER_DENOMINATION_RSA != keys[k].denom_pub.cipher)
+ continue;
+ {
+ struct TALER_PlanchetDetail pd[batch_size];
+ struct TALER_CRYPTO_RsaSignRequest rsr[batch_size];
+
+ for (unsigned int i = 0; i<batch_size; i++)
+ {
+ pd[i].blinded_planchet.cipher = TALER_DENOMINATION_RSA;
+ GNUNET_assert (GNUNET_YES ==
+ TALER_planchet_prepare (&keys[k].denom_pub,
+ &alg_values[i],
+ &bks[i],
+ &coin_priv[i],
+ &ach[i],
+ &c_hash[i],
+ &pd[i]));
+ rsr[i].h_rsa
+ = &keys[k].h_rsa;
+ rsr[i].msg
+ = pd[i].blinded_planchet.details.rsa_blinded_planchet.blinded_msg;
+ rsr[i].msg_size
+ = pd[i].blinded_planchet.details.rsa_blinded_planchet.blinded_msg_size;
+ }
+ ec = TALER_CRYPTO_helper_rsa_batch_sign (dh,
+ rsr,
+ batch_size,
+ ds);
+ for (unsigned int i = 0; i<batch_size; i++)
+ {
+ if (TALER_EC_NONE == ec)
+ GNUNET_break (TALER_DENOMINATION_RSA ==
+ ds[i].cipher);
+ TALER_blinded_planchet_free (&pd[i].blinded_planchet);
+ }
+ }
+ 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;
+ }
+ for (unsigned int i = 0; i<batch_size; i++)
+ {
+ struct TALER_DenominationSignature rs;
+
+ if (check_sigs)
+ {
+ if (GNUNET_OK !=
+ TALER_denom_sig_unblind (&rs,
+ &ds[i],
+ &bks[i],
+ &c_hash[i],
+ &alg_values[i],
+ &keys[k].denom_pub))
+ {
+ GNUNET_break (0);
+ return 6;
+ }
+ }
+ TALER_blinded_denom_sig_free (&ds[i]);
+ if (check_sigs)
+ {
+ if (GNUNET_OK !=
+ TALER_denom_pub_verify (&keys[k].denom_pub,
+ &rs,
+ &c_hash[i]))
+ {
+ /* signature invalid */
+ GNUNET_break (0);
+ TALER_denom_sig_free (&rs);
+ return 7;
+ }
+ TALER_denom_sig_free (&rs);
+ }
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ "Received valid signature for key %s\n",
+ GNUNET_h2s (&keys[k].h_rsa.hash));
+ success = true;
+ break;
+ case TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY:
+ /* This 'failure' is expected, we're testing also for the
+ error handling! */
+ for (unsigned int i = 0; i<batch_size; i++)
+ TALER_blinded_denom_sig_free (&ds[i]);
+ 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;
+ case TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN:
+ for (unsigned int i = 0; i<batch_size; i++)
+ TALER_blinded_denom_sig_free (&ds[i]);
+ default:
+ /* unexpected error */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected error %d at %s:%u\n",
+ ec,
+ __FILE__,
+ __LINE__);
+ for (unsigned int i = 0; i<batch_size; i++)
+ TALER_blinded_denom_sig_free (&ds[i]);
+ 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_RsaPubHashP rnd;
+ struct TALER_CRYPTO_RsaSignRequest rsr = {
+ .h_rsa = &rnd,
+ .msg = "Hello",
+ .msg_size = strlen ("Hello")
+ };
+
+ GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
+ &rnd,
+ sizeof (rnd));
+ ec = TALER_CRYPTO_helper_rsa_batch_sign (dh,
+ &rsr,
+ 1,
+ ds);
+ if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Signing with invalid key returned unexpected status %d\n",
+ 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
@@ -614,7 +831,8 @@ run_test (void)
return 77;
}
- fprintf (stderr, "Waiting for helper to start ... ");
+ fprintf (stderr,
+ "Waiting for helper to start ... ");
for (unsigned int i = 0; i<100; i++)
{
nanosleep (&req,
@@ -650,6 +868,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_rsa_disconnect (dh);