add support for batch signing in RSA

This commit is contained in:
Christian Grothoff 2022-11-13 14:46:43 +01:00
parent f2eba7b8b7
commit b93b9dd074
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
2 changed files with 406 additions and 150 deletions

View File

@ -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)
if (ret < 0)
{
GNUNET_assert (finished);
GNUNET_assert (0 == off);
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_UNAVAILABLE;
break;
}
if (0 == ret)
{
GNUNET_break (0 == off);
if (! finished)
ec = TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
if (TALER_EC_NONE == ec)
break;
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;
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 (off < sizeof (struct GNUNET_MessageHeader))
continue;
msize = ntohs (hdr->size);
if (off < msize)
continue;
switch (ntohs (hdr->type))
{
GNUNET_break_op (0);
do_disconnect (dh);
ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
goto end;
}
if (finished)
{
GNUNET_break_op (0);
do_disconnect (dh);
ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
goto end;
}
{
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;
}
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)
if (finished)
{
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;
{
const struct TALER_CRYPTO_SignResponse *sr =
(const struct TALER_CRYPTO_SignResponse *) buf;
struct GNUNET_CRYPTO_RsaSignature *rsa_signature;
ec = (enum TALER_ErrorCode) ntohl (sf->ec);
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,
"Signing failed!\n");
finished = true;
"Received new key!\n");
if (GNUNET_OK !=
handle_mt_avail (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_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);
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;
}

View File

@ -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
@ -440,6 +440,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.
*
@ -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,
@ -649,6 +867,34 @@ run_test (void)
ret = test_revocation (dh);
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");