complete crypto helper denom testing

This commit is contained in:
Christian Grothoff 2020-11-22 22:25:49 +01:00
parent 1931869c3c
commit 171391057d
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
5 changed files with 325 additions and 104 deletions

@ -1 +1 @@
Subproject commit e5ae01eeb4dedd8599473e64e098ea97fb7dadde
Subproject commit 8341d17cd88b1e88943f192a47fbc61ce925816c

View File

@ -51,7 +51,7 @@ libtalerutil_la_SOURCES = \
amount.c \
config.c \
crypto.c \
crypto_helper.c \
crypto_helper_denom.c \
crypto_wire.c \
getopt.c \
lang.c \

View File

@ -14,7 +14,7 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file util/crypto_helper.c
* @file util/crypto_helper_denom.c
* @brief utility functions for running out-of-process private key operations
* @author Christian Grothoff
*/
@ -238,6 +238,97 @@ TALER_CRYPTO_helper_denom_connect (
}
/**
* Handle a #TALER_HELPER_RSA_MT_AVAIL message from the helper.
*
* @param dh helper context
* @param hdr message that we received
* @return #GNUNET_OK on success
*/
static int
handle_mt_avail (struct TALER_CRYPTO_DenominationHelper *dh,
const struct GNUNET_MessageHeader *hdr)
{
const struct TALER_CRYPTO_RsaKeyAvailableNotification *kan
= (const struct TALER_CRYPTO_RsaKeyAvailableNotification *) hdr;
const char *buf = (const char *) &kan[1];
const char *section_name;
if (sizeof (*kan) > ntohs (hdr->size))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
if (ntohs (hdr->size) !=
sizeof (*kan)
+ ntohs (kan->pub_size)
+ ntohs (kan->section_name_len))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
section_name = &buf[ntohs (kan->pub_size)];
if ('\0' != section_name[ntohs (kan->section_name_len) - 1])
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
{
struct TALER_DenominationPublicKey denom_pub;
struct GNUNET_HashCode h_denom_pub;
denom_pub.rsa_public_key
= GNUNET_CRYPTO_rsa_public_key_decode (buf,
ntohs (kan->pub_size));
if (NULL == denom_pub.rsa_public_key)
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
GNUNET_CRYPTO_rsa_public_key_hash (denom_pub.rsa_public_key,
&h_denom_pub);
dh->dkc (dh->dkc_cls,
section_name,
GNUNET_TIME_absolute_ntoh (kan->anchor_time),
GNUNET_TIME_relative_ntoh (kan->duration_withdraw),
&h_denom_pub,
&denom_pub);
GNUNET_CRYPTO_rsa_public_key_free (denom_pub.rsa_public_key);
}
return GNUNET_OK;
}
/**
* Handle a #TALER_HELPER_RSA_MT_PURGE message from the helper.
*
* @param dh helper context
* @param hdr message that we received
* @return #GNUNET_OK on success
*/
static int
handle_mt_purge (struct TALER_CRYPTO_DenominationHelper *dh,
const struct GNUNET_MessageHeader *hdr)
{
const struct TALER_CRYPTO_RsaKeyPurgeNotification *pn
= (const struct TALER_CRYPTO_RsaKeyPurgeNotification *) hdr;
if (sizeof (*pn) != ntohs (hdr->size))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
dh->dkc (dh->dkc_cls,
NULL,
GNUNET_TIME_UNIT_ZERO_ABS,
GNUNET_TIME_UNIT_ZERO,
&pn->h_denom_pub,
NULL);
return GNUNET_OK;
}
void
TALER_CRYPTO_helper_poll (struct TALER_CRYPTO_DenominationHelper *dh)
{
@ -275,74 +366,24 @@ TALER_CRYPTO_helper_poll (struct TALER_CRYPTO_DenominationHelper *dh)
switch (ntohs (hdr->type))
{
case TALER_HELPER_RSA_MT_AVAIL:
{
const struct TALER_CRYPTO_RsaKeyAvailableNotification *kan
= (const struct TALER_CRYPTO_RsaKeyAvailableNotification *) buf;
const char *section_name;
struct TALER_DenominationPublicKey denom_pub;
struct GNUNET_HashCode h_denom_pub;
if (sizeof (*kan) > ret)
if (GNUNET_OK !=
handle_mt_avail (dh,
hdr))
{
GNUNET_break_op (0);
do_disconnect (dh);
return;
}
if (ret !=
sizeof (*kan)
+ ntohs (kan->pub_size)
+ ntohs (kan->section_name_len))
{
GNUNET_break_op (0);
do_disconnect (dh);
return;
}
if ('\0' != buf[ret - 1])
{
GNUNET_break_op (0);
do_disconnect (dh);
return;
}
denom_pub.rsa_public_key
= GNUNET_CRYPTO_rsa_public_key_decode (&buf[sizeof (*kan)],
ntohs (kan->pub_size));
if (NULL == denom_pub.rsa_public_key)
{
GNUNET_break_op (0);
do_disconnect (dh);
return;
}
section_name = &buf[sizeof (*kan) + ntohs (kan->pub_size)];
GNUNET_CRYPTO_rsa_public_key_hash (denom_pub.rsa_public_key,
&h_denom_pub);
dh->dkc (dh->dkc_cls,
section_name,
GNUNET_TIME_absolute_ntoh (kan->anchor_time),
GNUNET_TIME_relative_ntoh (kan->duration_withdraw),
&h_denom_pub,
&denom_pub);
GNUNET_CRYPTO_rsa_public_key_free (denom_pub.rsa_public_key);
}
break;
case TALER_HELPER_RSA_MT_PURGE:
{
const struct TALER_CRYPTO_RsaKeyPurgeNotification *pn
= (const struct TALER_CRYPTO_RsaKeyPurgeNotification *) buf;
if (sizeof (*pn) != ret)
if (GNUNET_OK !=
handle_mt_purge (dh,
hdr))
{
GNUNET_break_op (0);
do_disconnect (dh);
return;
}
dh->dkc (dh->dkc_cls,
NULL,
GNUNET_TIME_UNIT_ZERO_ABS,
GNUNET_TIME_UNIT_ZERO,
&pn->h_denom_pub,
NULL);
}
break;
default:
GNUNET_break_op (0);
@ -399,6 +440,7 @@ TALER_CRYPTO_helper_denom_sign (
GNUNET_break (((size_t) ret) == sizeof (buf));
}
while (1)
{
char buf[UINT16_MAX];
ssize_t ret;
@ -433,7 +475,7 @@ TALER_CRYPTO_helper_denom_sign (
GNUNET_break_op (0);
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
break;
return ds;
}
{
const struct TALER_CRYPTO_SignResponse *sr =
@ -447,7 +489,7 @@ TALER_CRYPTO_helper_denom_sign (
GNUNET_break_op (0);
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
break;
return ds;
}
*ec = TALER_EC_NONE;
ds.rsa_signature = rsa_signature;
@ -459,25 +501,44 @@ TALER_CRYPTO_helper_denom_sign (
GNUNET_break_op (0);
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
break;
return ds;
}
{
const struct TALER_CRYPTO_SignFailure *sf =
(const struct TALER_CRYPTO_SignFailure *) buf;
*ec = (enum TALER_ErrorCode) ntohl (sf->ec);
break;
return ds;
}
// FIXME: *could* also receive change in key status!
// Handle that here, and then try again!
case TALER_HELPER_RSA_MT_AVAIL:
if (GNUNET_OK !=
handle_mt_avail (dh,
hdr))
{
GNUNET_break_op (0);
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
return ds;
}
break; /* while(1) loop ensures we recvfrom() again */
case TALER_HELPER_RSA_MT_PURGE:
if (GNUNET_OK !=
handle_mt_purge (dh,
hdr))
{
GNUNET_break_op (0);
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
return ds;
}
break; /* while(1) loop ensures we recvfrom() again */
default:
GNUNET_break_op (0);
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
break;
}
}
return ds;
}
}
}
@ -524,4 +585,4 @@ TALER_CRYPTO_helper_denom_disconnect (
}
/* end of crypto_helper.c */
/* end of crypto_helper_denom.c */

View File

@ -551,6 +551,21 @@ handle_done (void *cls)
done_tail,
wi);
GNUNET_assert (0 == pthread_mutex_unlock (&done_lock));
if (NULL == wi->rsa_signature)
{
struct TALER_CRYPTO_SignFailure sf = {
.header.size = htons (sizeof (sf)),
.header.type = htons (TALER_HELPER_RSA_MT_RES_SIGN_FAILURE),
.ec = htonl (TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE)
};
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Signing request failed, worker failed to produce signature\n");
(void) transmit (&wi->addr,
wi->addr_size,
&sf.header);
}
else
{
struct TALER_CRYPTO_SignResponse *sr;
void *buf;
@ -598,7 +613,7 @@ handle_sign_request (const struct sockaddr_un *addr,
struct DenominationKey *dk;
struct WorkItem *wi;
const void *blinded_msg = &sr[1];
size_t blinded_msg_size = ntohs (sr->header.size) - sizeof (sr);
size_t blinded_msg_size = ntohs (sr->header.size) - sizeof (*sr);
dk = GNUNET_CONTAINER_multihashmap_get (keys,
&sr->h_denom_pub);
@ -618,9 +633,29 @@ handle_sign_request (const struct sockaddr_un *addr,
&sf.header);
return;
}
// FIXME: check denomination key is valid for signing
// at this time!
if (0 !=
GNUNET_TIME_absolute_get_remaining (dk->anchor).rel_value_us)
{
/* it is too early */
struct TALER_CRYPTO_SignFailure sf = {
.header.size = htons (sizeof (sr)),
.header.type = htons (TALER_HELPER_RSA_MT_RES_SIGN_FAILURE),
.ec = htonl (TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY)
};
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Signing request failed, denomination key %s is not yet valid\n",
GNUNET_h2s (&sr->h_denom_pub));
(void) transmit (addr,
addr_size,
&sf.header);
return;
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Received request to sign over %u bytes with key %s\n",
(unsigned int) blinded_msg_size,
GNUNET_h2s (&sr->h_denom_pub));
wi = GNUNET_new (struct WorkItem);
wi->addr = *addr;
wi->addr_size = addr_size;
@ -1038,11 +1073,13 @@ create_key (struct Denomination *denom)
{
struct DenominationKey *dk;
struct GNUNET_TIME_Absolute anchor;
struct GNUNET_TIME_Absolute now;
now = GNUNET_TIME_absolute_get ();
(void) GNUNET_TIME_round_abs (&now);
if (NULL == denom->keys_tail)
{
anchor = GNUNET_TIME_absolute_get ();
(void) GNUNET_TIME_round_abs (&anchor);
anchor = now;
}
else
{
@ -1050,6 +1087,8 @@ create_key (struct Denomination *denom)
GNUNET_TIME_relative_subtract (
denom->duration_withdraw,
overlap_duration));
if (now.abs_value_us > anchor.abs_value_us)
anchor = now;
}
dk = GNUNET_new (struct DenominationKey);
dk->denom = denom;

View File

@ -33,6 +33,11 @@
*/
#define NUM_REVOKES 10
/**
* How many iterations of the successful signing test should we run?
*/
#define NUM_SIGN_TESTS 100
/**
* Number of keys currently in #keys.
@ -189,7 +194,7 @@ test_revocation (struct TALER_CRYPTO_DenominationHelper *dh)
GNUNET_h2s (&keys[j].h_denom_pub));
TALER_CRYPTO_helper_denom_revoke (dh,
&keys[j].h_denom_pub);
for (unsigned int k = 0; k<80; k++)
for (unsigned int k = 0; k<1000; k++)
{
TALER_CRYPTO_helper_poll (dh);
if (! keys[j].revoked)
@ -205,6 +210,7 @@ test_revocation (struct TALER_CRYPTO_DenominationHelper *dh)
TALER_CRYPTO_helper_denom_disconnect (dh);
return 2;
}
fprintf (stderr, "\n");
break;
}
}
@ -225,7 +231,11 @@ test_signing (struct TALER_CRYPTO_DenominationHelper *dh)
enum TALER_ErrorCode ec;
bool success = false;
struct GNUNET_HashCode m_hash;
struct GNUNET_CRYPTO_RsaBlindingKeySecret bks;
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
&bks,
sizeof (bks));
GNUNET_CRYPTO_hash ("Hello",
strlen ("Hello"),
&m_hash);
@ -233,11 +243,26 @@ test_signing (struct TALER_CRYPTO_DenominationHelper *dh)
{
if (! keys[i].valid)
continue;
{
void *buf;
size_t buf_size;
GNUNET_assert (GNUNET_YES ==
GNUNET_CRYPTO_rsa_blind (&m_hash,
&bks,
keys[i].denom_pub.rsa_public_key,
&buf,
&buf_size));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Requesting signature over %u bytes with key %s\n",
(unsigned int) buf_size,
GNUNET_h2s (&keys[i].h_denom_pub));
ds = TALER_CRYPTO_helper_denom_sign (dh,
&keys[i].h_denom_pub,
&m_hash,
sizeof (m_hash),
buf,
buf_size,
&ec);
GNUNET_free (buf);
}
switch (ec)
{
case TALER_EC_NONE:
@ -255,21 +280,38 @@ test_signing (struct TALER_CRYPTO_DenominationHelper *dh)
GNUNET_break (0);
return 5;
}
{
struct GNUNET_CRYPTO_RsaSignature *rs;
rs = GNUNET_CRYPTO_rsa_unblind (ds.rsa_signature,
&bks,
keys[i].denom_pub.rsa_public_key);
if (NULL == rs)
{
GNUNET_break (0);
return 6;
}
GNUNET_CRYPTO_rsa_signature_free (ds.rsa_signature);
if (GNUNET_OK !=
GNUNET_CRYPTO_rsa_verify (&m_hash,
ds.rsa_signature,
rs,
keys[i].denom_pub.rsa_public_key))
{
/* signature invalid */
GNUNET_break (0);
GNUNET_CRYPTO_rsa_signature_free (ds.rsa_signature);
return 6;
GNUNET_CRYPTO_rsa_signature_free (rs);
return 7;
}
GNUNET_CRYPTO_rsa_signature_free (ds.rsa_signature);
GNUNET_CRYPTO_rsa_signature_free (rs);
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Received valid signature for key %s\n",
GNUNET_h2s (&keys[i].h_denom_pub));
success = true;
break;
#if FIXME
case TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_INVALID:
case TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY:
/* This 'failure' is expected, we're testing also for the
error handling! */
if ( (0 ==
GNUNET_TIME_absolute_get_remaining (
keys[i].start_time).rel_value_us) &&
@ -282,7 +324,6 @@ test_signing (struct TALER_CRYPTO_DenominationHelper *dh)
return 6;
}
break;
#endif
default:
/* unexpected error */
GNUNET_break (0);
@ -313,11 +354,94 @@ test_signing (struct TALER_CRYPTO_DenominationHelper *dh)
GNUNET_break (0);
return 17;
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Signing with invalid key %s failed as desired\n",
GNUNET_h2s (&rnd));
}
return 0;
}
/**
* Benchmark signing logic.
*
* @param dh handle to the helper
* @return 0 on success
*/
static int
perf_signing (struct TALER_CRYPTO_DenominationHelper *dh)
{
struct TALER_DenominationSignature ds;
enum TALER_ErrorCode ec;
bool success = false;
struct GNUNET_HashCode m_hash;
struct GNUNET_CRYPTO_RsaBlindingKeySecret bks;
struct GNUNET_TIME_Relative duration;
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
&bks,
sizeof (bks));
GNUNET_CRYPTO_hash ("Hello",
strlen ("Hello"),
&m_hash);
duration = GNUNET_TIME_UNIT_ZERO;
for (unsigned int j = 0; j<NUM_SIGN_TESTS;)
{
TALER_CRYPTO_helper_poll (dh);
for (unsigned int i = 0; i<MAX_KEYS; i++)
{
if (! keys[i].valid)
continue;
if (GNUNET_TIME_absolute_get_remaining (keys[i].start_time).rel_value_us >
GNUNET_TIME_UNIT_SECONDS.rel_value_us)
continue;
if (GNUNET_TIME_absolute_get_duration (keys[i].start_time).rel_value_us >
keys[i].validity_duration.rel_value_us)
continue;
{
void *buf;
size_t buf_size;
GNUNET_assert (GNUNET_YES ==
GNUNET_CRYPTO_rsa_blind (&m_hash,
&bks,
keys[i].denom_pub.rsa_public_key,
&buf,
&buf_size));
/* use this key as long as it works */
while (1)
{
struct GNUNET_TIME_Absolute start = GNUNET_TIME_absolute_get ();
struct GNUNET_TIME_Relative delay;
ds = TALER_CRYPTO_helper_denom_sign (dh,
&keys[i].h_denom_pub,
buf,
buf_size,
&ec);
if (TALER_EC_NONE != ec)
break;
delay = GNUNET_TIME_absolute_get_duration (start);
duration = GNUNET_TIME_relative_add (duration,
delay);
GNUNET_CRYPTO_rsa_signature_free (ds.rsa_signature);
j++;
if (NUM_SIGN_TESTS == j)
break;
}
GNUNET_free (buf);
}
} /* for i */
} /* for j */
fprintf (stderr,
"%u (sequential) signature operations took %s\n",
(unsigned int) NUM_SIGN_TESTS,
GNUNET_STRINGS_relative_time_to_string (duration,
GNUNET_YES));
return 0;
}
/**
* Main entry point into the test logic with the helper already running.
*/
@ -350,7 +474,7 @@ run_test (void)
}
/* wait for helper to start and give us keys */
fprintf (stderr, "Waiting for helper to start ");
for (unsigned int i = 0; i<80; i++)
for (unsigned int i = 0; i<1000; i++)
{
TALER_CRYPTO_helper_poll (dh);
if (0 != num_keys)
@ -370,15 +494,12 @@ run_test (void)
num_keys);
ret = 0;
#if 1
if (0 == ret)
ret = test_revocation (dh);
#endif
#if 0
if (0 == ret)
ret = test_signing (dh);
#endif
if (0 == ret)
ret = perf_signing (dh);
TALER_CRYPTO_helper_denom_disconnect (dh);
/* clean up our state */
for (unsigned int i = 0; i<MAX_KEYS; i++)
@ -407,7 +528,7 @@ main (int argc,
(void) argc;
(void) argv;
GNUNET_log_setup ("test-helper-rsa",
"INFO",
"WARNING",
NULL);
GNUNET_OS_init (TALER_project_data_default ());
libexec_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBEXECDIR);
@ -423,7 +544,7 @@ main (int argc,
"-c",
"test_helper_rsa.conf",
"-L",
"INFO",
"WARNING",
NULL);
if (NULL == helper)
{