diff options
author | Christian Grothoff <christian@grothoff.org> | 2020-11-22 18:31:33 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2020-11-22 18:31:33 +0100 |
commit | a9fb94e916ba6084997571f03fd6c2b4d557576b (patch) | |
tree | be306998212283fa32591308a583bb189c195b22 | |
parent | 9b68dbb8e6c873ff40c00da85b3a9f709afd42e1 (diff) |
start with testing crypto rsa helper
-rw-r--r-- | src/util/.gitignore | 1 | ||||
-rw-r--r-- | src/util/Makefile.am | 14 | ||||
-rw-r--r-- | src/util/crypto_helper.c | 161 | ||||
-rw-r--r-- | src/util/taler-helper-crypto-rsa.c | 368 | ||||
-rw-r--r-- | src/util/taler-helper-crypto-rsa.h | 9 | ||||
-rw-r--r-- | src/util/test_helper_rsa.c | 314 | ||||
-rw-r--r-- | src/util/test_helper_rsa.conf | 9 |
7 files changed, 657 insertions, 219 deletions
diff --git a/src/util/.gitignore b/src/util/.gitignore index 8409f61d6..8a8cc0524 100644 --- a/src/util/.gitignore +++ b/src/util/.gitignore @@ -1,3 +1,4 @@ taler-config test_payto taler-helper-crypto-rsa +test_helper_rsa diff --git a/src/util/Makefile.am b/src/util/Makefile.am index c74fe2101..505634381 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -7,7 +7,7 @@ if USE_COVERAGE endif -libexecdir = $(pkglibdir)/libexec/ +libexecdir = $(libdir)/taler/libexec pkgcfgdir = $(prefix)/share/taler/config.d/ @@ -17,7 +17,8 @@ pkgcfg_DATA = \ EXTRA_DIST = \ paths.conf \ - taler-config.in + taler-config.in \ + test_helper_rsa.conf libexec_PROGRAMS = \ taler-helper-crypto-rsa @@ -72,9 +73,12 @@ libtalerutil_la_LDFLAGS = \ -export-dynamic -no-undefined +AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=$${TALER_PREFIX:-@prefix@}/bin:$$PATH; + check_PROGRAMS = \ test_amount \ test_crypto \ + test_helper_rsa \ test_payto \ test_url @@ -100,6 +104,12 @@ test_payto_LDADD = \ -lgnunetutil \ libtalerutil.la +test_helper_rsa_SOURCES = \ + test_helper_rsa.c +test_helper_rsa_LDADD = \ + -lgnunetutil \ + libtalerutil.la + test_url_SOURCES = \ test_url.c test_url_LDADD = \ diff --git a/src/util/crypto_helper.c b/src/util/crypto_helper.c index 2b0fbe468..c42f01fc3 100644 --- a/src/util/crypto_helper.c +++ b/src/util/crypto_helper.c @@ -42,6 +42,16 @@ struct TALER_CRYPTO_DenominationHelper struct sockaddr_un sa; /** + * Socket address of this process. + */ + struct sockaddr_un my_sa; + + /** + * Template for @e my_sa. + */ + char *template; + + /** * The UNIX domain socket, -1 if we are currently not connected. */ int sock; @@ -58,6 +68,10 @@ static void do_disconnect (struct TALER_CRYPTO_DenominationHelper *dh) { GNUNET_break (0 == close (dh->sock)); + if (0 != unlink (dh->my_sa.sun_path)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, + "unlink", + dh->my_sa.sun_path); dh->sock = -1; } @@ -82,18 +96,73 @@ try_connect (struct TALER_CRYPTO_DenominationHelper *dh) "socket"); return; } - if (0 != connect (dh->sock, - (const struct sockaddr *) &dh->sa, - sizeof (dh->sa))) { - if (EINPROGRESS != dh->sock) + char *tmpdir; + + tmpdir = GNUNET_DISK_mktemp (dh->template); + if (NULL == tmpdir) { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, - "connect"); do_disconnect (dh); return; } + /* we use >= here because we want the sun_path to always + be 0-terminated */ + if (strlen (tmpdir) >= sizeof (dh->sa.sun_path)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + "PATHS", + "TALER_RUNTIME_DIR", + "path too long"); + GNUNET_free (tmpdir); + do_disconnect (dh); + return; + } + dh->my_sa.sun_family = AF_UNIX; + strncpy (dh->my_sa.sun_path, + tmpdir, + sizeof (dh->sa.sun_path)); + if (0 != unlink (tmpdir)) + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, + "unlink", + tmpdir); + GNUNET_free (tmpdir); } + if (0 != bind (dh->sock, + (const struct sockaddr *) &dh->my_sa, + sizeof (dh->my_sa))) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "bind"); + do_disconnect (dh); + return; + } + { + struct GNUNET_MessageHeader hdr = { + .size = htons (sizeof (hdr)), + .type = htons (TALER_HELPER_RSA_MT_REQ_INIT) + }; + ssize_t ret; + + ret = sendto (dh->sock, + &hdr, + sizeof (hdr), + 0, + (const struct sockaddr *) &dh->sa, + sizeof (dh->sa)); + if (ret < 0) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING, + "sendto", + dh->sa.sun_path); + do_disconnect (dh); + return; + } + /* We are using SOCK_DGRAM, partial writes should not be possible */ + GNUNET_break (((size_t) ret) == sizeof (hdr)); + GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + "Successfully sent REQ_INIT\n"); + } + } @@ -117,7 +186,9 @@ TALER_CRYPTO_helper_denom_connect ( "UNIXPATH"); return NULL; } - if (strlen (unixpath) > sizeof (dh->sa.sun_path)) + /* we use >= here because we want the sun_path to always + be 0-terminated */ + if (strlen (unixpath) >= sizeof (dh->sa.sun_path)) { GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, "taler-helper-crypto-rsa", @@ -129,10 +200,39 @@ TALER_CRYPTO_helper_denom_connect ( dh = GNUNET_new (struct TALER_CRYPTO_DenominationHelper); dh->dkc = dkc; dh->dkc_cls = dkc_cls; + dh->sa.sun_family = AF_UNIX; strncpy (dh->sa.sun_path, unixpath, sizeof (dh->sa.sun_path)); dh->sock = -1; + { + char *tmpdir; + char *template; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_filename (cfg, + "PATHS", + "TALER_RUNTIME_DIR", + &tmpdir)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, + "PATHS", + "TALER_RUNTIME_DIR"); + tmpdir = GNUNET_strdup ("/tmp"); + } + GNUNET_asprintf (&template, + "%s/crypto-rsa-client/XXXXXX", + tmpdir); + GNUNET_free (tmpdir); + if (GNUNET_OK != + GNUNET_DISK_directory_create_for_file (template)) + { + GNUNET_free (dh); + GNUNET_free (template); + return NULL; + } + dh->template = template; + } TALER_CRYPTO_helper_poll (dh); return dh; } @@ -157,6 +257,8 @@ TALER_CRYPTO_helper_poll (struct TALER_CRYPTO_DenominationHelper *dh) MSG_DONTWAIT); if (ret < 0) { + if (EAGAIN == errno) + break; GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "recv"); do_disconnect (dh); @@ -180,10 +282,22 @@ TALER_CRYPTO_helper_poll (struct TALER_CRYPTO_DenominationHelper *dh) struct TALER_DenominationPublicKey denom_pub; struct GNUNET_HashCode h_denom_pub; - if ( (sizeof (*kan) < ret) || - (sizeof (*kan) + ntohs (kan->pub_size) + ntohs ( - kan->section_name_len)) || - ('\0' != buf[ret - 1]) ) + if (sizeof (*kan) > ret) + { + 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); @@ -267,14 +381,16 @@ TALER_CRYPTO_helper_denom_sign ( memcpy (&sr[1], msg, msg_size); - ret = send (dh->sock, - buf, - sizeof (buf), - 0); + ret = sendto (dh->sock, + buf, + sizeof (buf), + 0, + &dh->sa, + sizeof (dh->sa)); if (ret < 0) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, - "send"); + "sendto"); do_disconnect (dh); *ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE; return ds; @@ -378,14 +494,16 @@ TALER_CRYPTO_helper_denom_revoke ( try_connect (dh); if (-1 == dh->sock) return; /* give up */ - ret = send (dh->sock, - &rr, - sizeof (rr), - 0); + ret = sendto (dh->sock, + &rr, + sizeof (rr), + 0, + (const struct sockaddr *) &dh->sa, + sizeof (dh->sa)); if (ret < 0) { GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, - "send"); + "sendto"); do_disconnect (dh); return; } @@ -399,6 +517,7 @@ TALER_CRYPTO_helper_denom_disconnect ( struct TALER_CRYPTO_DenominationHelper *dh) { do_disconnect (dh); + GNUNET_free (dh->template); GNUNET_free (dh); } diff --git a/src/util/taler-helper-crypto-rsa.c b/src/util/taler-helper-crypto-rsa.c index 92485571f..2d57fe75a 100644 --- a/src/util/taler-helper-crypto-rsa.c +++ b/src/util/taler-helper-crypto-rsa.c @@ -92,7 +92,7 @@ struct DenominationKey /** * Hash of this denomination's public key. */ - struct GNUNET_HashCode h_pub; + struct GNUNET_HashCode h_denom_pub; /** * Time at which this key is supposed to become valid. @@ -181,26 +181,14 @@ struct Client struct Client *prev; /** - * Work created by this client, NULL for none. + * Client address. */ - struct WorkItem *work; + struct sockaddr_un addr; /** - * Client socket. + * Number of bytes used in @e addr. */ - struct GNUNET_NETWORK_Handle *sock; - - /** - * Client task to read from @e sock. NULL if we are working. - */ - struct GNUNET_SCHEDULER_Task *task; - - /** - * Flag set to true if this client has disconnected. Used - * by the workers to detect that they must free the client - * instead of returning the result. - */ - bool gone; + socklen_t addr_size; }; @@ -219,11 +207,6 @@ struct WorkItem struct WorkItem *prev; /** - * The client that created the request. - */ - struct Client *client; - - /** * Key to be used for this operation. */ struct DenominationKey *dk; @@ -244,6 +227,16 @@ struct WorkItem */ size_t blinded_msg_size; + /** + * Client address. + */ + struct sockaddr_un addr; + + /** + * Number of bytes used in @e addr. + */ + socklen_t addr_size; + }; @@ -305,7 +298,7 @@ static struct GNUNET_CONTAINER_MultiHashMap *keys; /** * Our listen socket. */ -static struct GNUNET_NETWORK_Handle *lsock; +static struct GNUNET_NETWORK_Handle *unix_sock; /** * Path where we are listening. @@ -315,7 +308,7 @@ static char *unixpath; /** * Task run to accept new inbound connections. */ -static struct GNUNET_SCHEDULER_Task *accept_task; +static struct GNUNET_SCHEDULER_Task *read_task; /** * Task run to generate new keys. @@ -464,20 +457,10 @@ sign_worker (void *cls) static void free_client (struct Client *client) { - if (NULL != client->task) - { - GNUNET_SCHEDULER_cancel (client->task); - client->task = NULL; - } - GNUNET_NETWORK_socket_close (client->sock); - client->sock = NULL; GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, client); - if (NULL != client->work) - client->gone = true; - else - GNUNET_free (client); + GNUNET_free (client); } @@ -491,21 +474,6 @@ read_job (void *cls); /** - * Start reading requests from the @a client. - * - * @param client client to read requests from. - */ -static void -client_next (struct Client *client) -{ - client->task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, - client->sock, - &read_job, - client); -} - - -/** * Free @a dk. It must already have been removed from #keys and the * denomination's DLL. * @@ -524,25 +492,27 @@ free_dk (struct DenominationKey *dk) /** * Send a message starting with @a hdr to @a client. * - * @param client where to send @a hdr + * @param addr address where to send the message + * @param addr_size number of bytes in @a addr * @param hdr beginning of the message, length indicated in size field * @return #GNUNET_OK on success */ static int -transmit_to_client (struct Client *client, - const struct GNUNET_MessageHeader *hdr) +transmit (const struct sockaddr_un *addr, + socklen_t addr_size, + const struct GNUNET_MessageHeader *hdr) { ssize_t ret; - ret = send (GNUNET_NETWORK_get_fd (client->sock), - hdr, - ntohs (hdr->size), - 0); + ret = GNUNET_NETWORK_socket_sendto (unix_sock, + hdr, + ntohs (hdr->size), + (const struct sockaddr *) addr, + addr_size); if (ret != ntohs (hdr->size)) { - GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, - "send"); - free_client (client); + GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO, + "sendto"); return GNUNET_SYSERR; } return GNUNET_OK; @@ -598,8 +568,9 @@ handle_done (void *cls) buf, buf_size); GNUNET_free (buf); - (void) transmit_to_client (wi->client, - &sr->header); + (void) transmit (&wi->addr, + wi->addr_size, + &sr->header); GNUNET_free (sr); } GNUNET_free (wi); @@ -615,11 +586,13 @@ handle_done (void *cls) * signature using the respective key and return the result to * the client. * - * @param client the client making the request + * @param addr address of the client making the request + * @param addr_size number of bytes in @a addr * @param sr the request details */ static void -handle_sign_request (struct Client *client, +handle_sign_request (const struct sockaddr_un *addr, + socklen_t addr_size, const struct TALER_CRYPTO_SignRequest *sr) { struct DenominationKey *dk; @@ -638,15 +611,17 @@ handle_sign_request (struct Client *client, }; GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Signing request failed, denomination key unknown\n"); - transmit_to_client (client, - &sf.header); - client_next (client); + "Signing request failed, denomination key %s unknown\n", + GNUNET_h2s (&sr->h_denom_pub)); + (void) transmit (addr, + addr_size, + &sf.header); return; } wi = GNUNET_new (struct WorkItem); - wi->client = client; + wi->addr = *addr; + wi->addr_size = addr_size; wi->dk = dk; dk->rc++; wi->blinded_msg = GNUNET_memdup (blinded_msg, @@ -680,7 +655,6 @@ notify_client_dk_add (struct Client *client, void *buf; void *p; size_t tlen; - int ret; buf_len = GNUNET_CRYPTO_rsa_public_key_encode (dk->denom_pub.rsa_public_key, &buf); @@ -703,10 +677,23 @@ notify_client_dk_add (struct Client *client, memcpy (p + buf_len, denom->section, nlen); - ret = transmit_to_client (client, - &an->header); - GNUNET_free (an); - return ret; + { + int ret = GNUNET_OK; + + if (GNUNET_OK != + transmit (&client->addr, + client->addr_size, + &an->header)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Client %s must have disconnected\n", + client->addr.sun_path); + free_client (client); + ret = GNUNET_SYSERR; + } + GNUNET_free (an); + return ret; + } } @@ -724,11 +711,21 @@ notify_client_dk_del (struct Client *client, struct TALER_CRYPTO_RsaKeyPurgeNotification pn = { .header.type = htons (TALER_HELPER_RSA_MT_PURGE), .header.size = htons (sizeof (pn)), - .h_denom_pub = dk->h_pub + .h_denom_pub = dk->h_denom_pub }; - return transmit_to_client (client, - &pn.header); + if (GNUNET_OK != + transmit (&client->addr, + client->addr_size, + &pn.header)) + { + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Client %s must have disconnected\n", + client->addr.sun_path); + free_client (client); + return GNUNET_SYSERR; + } + return GNUNET_OK; } @@ -767,7 +764,7 @@ setup_key (struct DenominationKey *dk, buf_size = GNUNET_CRYPTO_rsa_private_key_encode (priv, &buf); GNUNET_CRYPTO_rsa_public_key_hash (pub, - &dk->h_pub); + &dk->h_denom_pub); GNUNET_asprintf (&dk->filename, "%s/%s/%llu", keydir, @@ -789,13 +786,17 @@ setup_key (struct DenominationKey *dk, return GNUNET_SYSERR; } GNUNET_free (buf); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Setup fresh private key %s in `%s'\n", + GNUNET_h2s (&dk->h_denom_pub), + dk->filename); dk->denom_priv.rsa_private_key = priv; dk->denom_pub.rsa_public_key = pub; if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put ( keys, - &dk->h_pub, + &dk->h_denom_pub, dk, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) { @@ -839,11 +840,13 @@ setup_key (struct DenominationKey *dk, * Check if the key is still in use, and if so replace (!) * it with a fresh key. * - * @param client the client sending the request + * @param addr address of the client making the request + * @param addr_size number of bytes in @a addr * @param rr the revocation request */ static void -handle_revoke_request (struct Client *client, +handle_revoke_request (const struct sockaddr_un *addr, + socklen_t addr_size, const struct TALER_CRYPTO_RevokeRequest *rr) { struct DenominationKey *dk; @@ -854,9 +857,9 @@ handle_revoke_request (struct Client *client, &rr->h_denom_pub); if (NULL == dk) { - GNUNET_log (GNUNET_ERROR_TYPE_INFO, - "Revocation request ignored, denomination key unknown\n"); - client_next (client); + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Revocation request ignored, denomination key %s unknown\n", + GNUNET_h2s (&rr->h_denom_pub)); return; } @@ -886,11 +889,13 @@ handle_revoke_request (struct Client *client, GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove ( keys, - &dk->h_pub, + &dk->h_denom_pub, dk)); GNUNET_CONTAINER_DLL_remove (denom->keys_head, denom->keys_tail, dk); + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Revocation complete\n"); /* Tell clients this key is gone */ { @@ -910,8 +915,6 @@ handle_revoke_request (struct Client *client, } if (0 == dk->rc) free_dk (dk); - - client_next (client); } @@ -921,130 +924,108 @@ read_job (void *cls) struct Client *client = cls; char buf[65536]; ssize_t buf_size; - struct GNUNET_MessageHeader hdr; + const struct GNUNET_MessageHeader *hdr; + struct sockaddr_un addr; + socklen_t addr_size = sizeof (addr); - client->task = NULL; - buf_size = GNUNET_NETWORK_socket_recv (client->sock, - buf, - sizeof (buf)); + read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, + unix_sock, + &read_job, + NULL); + buf_size = GNUNET_NETWORK_socket_recvfrom (unix_sock, + buf, + sizeof (buf), + (struct sockaddr *) &addr, + &addr_size); if (-1 == buf_size) { - if (EAGAIN == errno) - { - client_next (client); - return; - } GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "recv"); - free_client (client); return; } if (0 == buf_size) { - free_client (client); return; } - if (buf_size < sizeof (hdr)) + if (buf_size < sizeof (struct GNUNET_MessageHeader)) { GNUNET_break_op (0); - free_client (client); return; } - memcpy (&hdr, - buf, - sizeof (hdr)); - if (ntohs (hdr.size) != buf_size) + hdr = (const struct GNUNET_MessageHeader *) buf; + if (ntohs (hdr->size) != buf_size) { GNUNET_break_op (0); free_client (client); return; } - switch (ntohs (hdr.type)) + switch (ntohs (hdr->type)) { + case TALER_HELPER_RSA_MT_REQ_INIT: + if (ntohs (hdr->size) != sizeof (struct GNUNET_MessageHeader)) + { + GNUNET_break_op (0); + return; + } + { + struct Client *client; + + client = GNUNET_new (struct Client); + client->addr = addr; + client->addr_size = addr_size; + GNUNET_CONTAINER_DLL_insert (clients_head, + clients_tail, + client); + for (struct Denomination *denom = denom_head; + NULL != denom; + denom = denom->next) + { + for (struct DenominationKey *dk = denom->keys_head; + NULL != dk; + dk = dk->next) + { + if (GNUNET_OK != + notify_client_dk_add (client, + dk)) + { + /* client died, skip the rest */ + client = NULL; + break; + } + } + if (NULL == client) + break; + } + } + break; case TALER_HELPER_RSA_MT_REQ_SIGN: - if (ntohs (hdr.size) <= sizeof (struct TALER_CRYPTO_SignRequest)) + if (ntohs (hdr->size) <= sizeof (struct TALER_CRYPTO_SignRequest)) { GNUNET_break_op (0); - free_client (client); return; } - handle_sign_request (client, - (const struct TALER_CRYPTO_SignRequest *) &hdr); + handle_sign_request (&addr, + addr_size, + (const struct TALER_CRYPTO_SignRequest *) buf); break; case TALER_HELPER_RSA_MT_REQ_REVOKE: - if (ntohs (hdr.size) != sizeof (struct TALER_CRYPTO_RevokeRequest)) + if (ntohs (hdr->size) != sizeof (struct TALER_CRYPTO_RevokeRequest)) { GNUNET_break_op (0); - free_client (client); return; } - handle_revoke_request (client, - (const struct TALER_CRYPTO_RevokeRequest *) &hdr); + handle_revoke_request (&addr, + addr_size, + (const struct TALER_CRYPTO_RevokeRequest *) buf); break; default: GNUNET_break_op (0); - free_client (client); return; } } /** - * Function run to accept incoming connections on #sock. - * - * @param cls NULL - */ -static void -accept_job (void *cls) -{ - struct GNUNET_NETWORK_Handle *sock; - struct sockaddr_storage addr; - socklen_t alen; - - accept_task = NULL; - alen = sizeof (addr); - sock = GNUNET_NETWORK_socket_accept (lsock, - (struct sockaddr *) &addr, - &alen); - if (NULL != sock) - { - struct Client *client; - - client = GNUNET_new (struct Client); - client->sock = sock; - GNUNET_CONTAINER_DLL_insert (clients_head, - clients_tail, - client); - client_next (client); - for (struct Denomination *denom = denom_head; - NULL != denom; - denom = denom->next) - { - for (struct DenominationKey *dk = denom->keys_head; - NULL != dk; - dk = dk->next) - { - if (GNUNET_OK != - notify_client_dk_add (client, - dk)) - { - /* client died, skip the rest */ - client = NULL; - break; - } - } - if (NULL == client) - break; - } - } - accept_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, - lsock, - &accept_job, - NULL); -} - - -/** * Create a new denomination key (we do not have enough). * * @param denom denomination key to create @@ -1137,7 +1118,7 @@ purge_key (struct DenominationKey *dk) dk); GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multihashmap_remove (keys, - &dk->h_pub, + &dk->h_denom_pub, dk)); if (0 != unlink (dk->filename)) { @@ -1325,17 +1306,18 @@ parse_key (struct Denomination *denom, dk->anchor = anchor; dk->filename = GNUNET_strdup (filename); GNUNET_CRYPTO_rsa_public_key_hash (pub, - &dk->h_pub); + &dk->h_denom_pub); dk->denom_pub.rsa_public_key = pub; if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put ( keys, - &dk->h_pub, + &dk->h_denom_pub, dk, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)) { GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Duplicate private key detected in file `%s'. Skipping.\n", + "Duplicate private key %s detected in file `%s'. Skipping.\n", + GNUNET_h2s (&dk->h_denom_pub), filename); GNUNET_CRYPTO_rsa_private_key_free (priv); GNUNET_CRYPTO_rsa_public_key_free (pub); @@ -1355,8 +1337,9 @@ parse_key (struct Denomination *denom, denom->keys_tail, before, dk); - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, - "Imported key from `%s'\n", + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Imported key %s from `%s'\n", + GNUNET_h2s (&dk->h_denom_pub), filename); } } @@ -1566,7 +1549,7 @@ load_denominations (void *cls, GNUNET_free (denom); return; } - GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, + GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Loading keys for denomination %s\n", denom->section); { @@ -1576,6 +1559,8 @@ load_denominations (void *cls, "%s/%s", keydir, denom->section); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_directory_create (dname)); GNUNET_DISK_directory_scan (dname, &import_key, denom); @@ -1611,17 +1596,16 @@ load_durations (void) if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (kcfg, - "exchange", + "taler-helper-crypto-rsa", "LOOKAHEAD_SIGN", &lookahead_sign)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "exchange", + "taler-helper-crypto-rsa", "LOOKAHEAD_SIGN"); return GNUNET_SYSERR; } GNUNET_TIME_round_rel (&lookahead_sign); - return GNUNET_OK; } @@ -1635,16 +1619,16 @@ static void do_shutdown (void *cls) { (void) cls; - if (NULL != accept_task) + if (NULL != read_task) { - GNUNET_SCHEDULER_cancel (accept_task); - accept_task = NULL; + GNUNET_SCHEDULER_cancel (read_task); + read_task = NULL; } - if (NULL != lsock) + if (NULL != unix_sock) { GNUNET_break (GNUNET_OK == - GNUNET_NETWORK_socket_close (lsock)); - lsock = NULL; + GNUNET_NETWORK_socket_close (unix_sock)); + unix_sock = NULL; } if (0 != unlink (unixpath)) { @@ -1790,7 +1774,7 @@ run (void *cls, return; } } - lsock = GNUNET_NETWORK_socket_box_native (sock); + unix_sock = GNUNET_NETWORK_socket_box_native (sock); } GNUNET_SCHEDULER_add_shutdown (&do_shutdown, @@ -1823,10 +1807,10 @@ run (void *cls, } /* start job to accept incoming requests on 'sock' */ - accept_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, - lsock, - &accept_job, - NULL); + read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, + unix_sock, + &read_job, + NULL); /* start job to keep keys up-to-date */ keygen_task = GNUNET_SCHEDULER_add_now (&update_denominations, @@ -1893,7 +1877,7 @@ main (int argc, /* force linker to link against libtalerutil; if we do not do this, the linker may "optimize" libtalerutil away and skip #TALER_OS_init(), which we do need */ - (void) TALER_project_data_default (); + GNUNET_OS_init (TALER_project_data_default ()); GNUNET_assert (GNUNET_OK == GNUNET_log_setup ("taler-helper-crypto-rsa", "WARNING", diff --git a/src/util/taler-helper-crypto-rsa.h b/src/util/taler-helper-crypto-rsa.h index a80c32e67..d2bc07f7a 100644 --- a/src/util/taler-helper-crypto-rsa.h +++ b/src/util/taler-helper-crypto-rsa.h @@ -24,11 +24,12 @@ #define TALER_HELPER_RSA_MT_PURGE 1 #define TALER_HELPER_RSA_MT_AVAIL 2 -#define TALER_HELPER_RSA_MT_REQ_SIGN 3 -#define TALER_HELPER_RSA_MT_REQ_REVOKE 4 +#define TALER_HELPER_RSA_MT_REQ_INIT 4 +#define TALER_HELPER_RSA_MT_REQ_SIGN 5 +#define TALER_HELPER_RSA_MT_REQ_REVOKE 6 -#define TALER_HELPER_RSA_MT_RES_SIGNATURE 5 -#define TALER_HELPER_RSA_MT_RES_SIGN_FAILURE 6 +#define TALER_HELPER_RSA_MT_RES_SIGNATURE 7 +#define TALER_HELPER_RSA_MT_RES_SIGN_FAILURE 8 GNUNET_NETWORK_STRUCT_BEGIN diff --git a/src/util/test_helper_rsa.c b/src/util/test_helper_rsa.c new file mode 100644 index 000000000..4cb4a5f18 --- /dev/null +++ b/src/util/test_helper_rsa.c @@ -0,0 +1,314 @@ +/* + This file is part of TALER + (C) 2020 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 + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/> +*/ +/** + * @file util/test_helper_rsa.c + * @brief Tests for RSA crypto helper + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_util.h" + +/** + * Configuration has 1 minute duration and 5 minutes lookahead, so + * we should never have more than 6 active keys, plus for during + * key expiration / revocation. + */ +#define MAX_KEYS 7 + +/** + * How many random key revocations should we test? + */ +#define NUM_REVOKES 10 + + +/** + * Number of keys currently in #keys. + */ +static unsigned int num_keys; + +/** + * Keys currently managed by the helper. + */ +struct KeyData +{ + /** + * Validity start point. + */ + struct GNUNET_TIME_Absolute start_time; + + /** + * Key expires for signing at @e start_time plus this value. + */ + struct GNUNET_TIME_Relative validity_duration; + + /** + * Hash of the public key. + */ + struct GNUNET_HashCode h_denom_pub; + + /** + * Full public key. + */ + struct TALER_DenominationPublicKey denom_pub; + + /** + * Is this key currently valid? + */ + bool valid; + + /** + * Did the test driver revoke this key? + */ + bool revoked; +}; + +static struct KeyData keys[MAX_KEYS]; + + +static void +key_cb (void *cls, + const char *section_name, + struct GNUNET_TIME_Absolute start_time, + struct GNUNET_TIME_Relative validity_duration, + const struct GNUNET_HashCode *h_denom_pub, + const struct TALER_DenominationPublicKey *denom_pub) +{ + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Key notification about key %s in `%s'\n", + GNUNET_h2s (h_denom_pub), + section_name); + if (0 == validity_duration.rel_value_us) + { + bool found = false; + + GNUNET_break (NULL == denom_pub); + GNUNET_break (NULL == section_name); + for (unsigned int i = 0; i<MAX_KEYS; i++) + if (0 == GNUNET_memcmp (h_denom_pub, + &keys[i].h_denom_pub)) + { + keys[i].valid = false; + keys[i].revoked = false; + GNUNET_CRYPTO_rsa_public_key_free (keys[i].denom_pub.rsa_public_key); + keys[i].denom_pub.rsa_public_key = NULL; + GNUNET_assert (num_keys > 0); + num_keys--; + found = true; + break; + } + if (! found) + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error: helper announced expiration of unknown key!\n"); + + return; + } + GNUNET_break (NULL != denom_pub); + for (unsigned int i = 0; i<MAX_KEYS; i++) + if (! keys[i].valid) + { + keys[i].valid = true; + keys[i].h_denom_pub = *h_denom_pub; + keys[i].start_time = start_time; + keys[i].validity_duration = validity_duration; + keys[i].denom_pub.rsa_public_key + = GNUNET_CRYPTO_rsa_public_key_dup (denom_pub->rsa_public_key); + num_keys++; + return; + } + /* too many keys! */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Error: received %d live keys from the service!\n", + MAX_KEYS + 1); +} + + +/** + * Main entry point into the test logic with the helper already running. + */ +static int +run_test (void) +{ + struct GNUNET_CONFIGURATION_Handle *cfg; + struct TALER_CRYPTO_DenominationHelper *dh; + struct timespec req = { + .tv_nsec = 250000000 + }; + + cfg = GNUNET_CONFIGURATION_create (); + if (GNUNET_OK != + GNUNET_CONFIGURATION_load (cfg, + "test_helper_rsa.conf")) + { + GNUNET_break (0); + return 77; + } + dh = TALER_CRYPTO_helper_denom_connect (cfg, + &key_cb, + NULL); + GNUNET_CONFIGURATION_destroy (cfg); + if (NULL == dh) + { + GNUNET_break (0); + return 1; + } + /* wait for helper to start and give us keys */ + fprintf (stderr, "Waiting for helper to start "); + for (unsigned int i = 0; i<80; i++) + { + TALER_CRYPTO_helper_poll (dh); + if (0 != num_keys) + break; + nanosleep (&req, NULL); + fprintf (stderr, "."); + } + if (0 == num_keys) + { + fprintf (stderr, + "\nFAILED: timeout trying to connect to helper\n"); + TALER_CRYPTO_helper_denom_disconnect (dh); + return 1; + } + fprintf (stderr, + "\nOK: Helper ready (%u keys)\n", + num_keys); + for (unsigned int i = 0; i<NUM_REVOKES; i++) + { + uint32_t off; + + off = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, + num_keys); + /* find index of key to revoke */ + for (unsigned int j = 0; j < MAX_KEYS; j++) + { + if (! keys[j].valid) + continue; + if (0 != off) + { + off--; + continue; + } + keys[j].revoked = true; + fprintf (stderr, + "Revoking key %s ...", + 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++) + { + TALER_CRYPTO_helper_poll (dh); + if (! keys[j].revoked) + break; + nanosleep (&req, NULL); + fprintf (stderr, "."); + } + if (keys[j].revoked) + { + fprintf (stderr, + "\nFAILED: timeout trying to revoke key %u\n", + j); + TALER_CRYPTO_helper_denom_disconnect (dh); + return 2; + } + break; + } + } + + + TALER_CRYPTO_helper_denom_disconnect (dh); + /* clean up our state */ + for (unsigned int i = 0; i<MAX_KEYS; i++) + if (keys[i].valid) + { + GNUNET_CRYPTO_rsa_public_key_free (keys[i].denom_pub.rsa_public_key); + keys[i].denom_pub.rsa_public_key = NULL; + GNUNET_assert (num_keys > 0); + num_keys--; + } + return 0; +} + + +int +main (int argc, + const char *const argv[]) +{ + struct GNUNET_OS_Process *helper; + char *libexec_dir; + char *binary_name; + int ret; + enum GNUNET_OS_ProcessStatusType type; + unsigned long code; + + (void) argc; + (void) argv; + GNUNET_log_setup ("test-helper-rsa", + "INFO", + NULL); + GNUNET_OS_init (TALER_project_data_default ()); + libexec_dir = GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LIBEXECDIR); + GNUNET_asprintf (&binary_name, + "%s/%s", + libexec_dir, + "taler-helper-crypto-rsa"); + GNUNET_free (libexec_dir); + helper = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ERR, + NULL, NULL, NULL, + binary_name, + binary_name, + "-c", + "test_helper_rsa.conf", + "-L", + "INFO", + NULL); + if (NULL == helper) + { + GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, + "exec", + binary_name); + GNUNET_free (binary_name); + return 77; + } + GNUNET_free (binary_name); + ret = run_test (); + + GNUNET_OS_process_kill (helper, + SIGTERM); + if (GNUNET_OK != + GNUNET_OS_process_wait_status (helper, + &type, + &code)) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Helper process did not die voluntarily, killing hard\n"); + GNUNET_OS_process_kill (helper, + SIGKILL); + ret = 4; + } + else if ( (GNUNET_OS_PROCESS_EXITED != type) || + (0 != code) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Helper died with unexpected status %d/%d\n", + (int) type, + (int) code); + ret = 5; + } + GNUNET_OS_process_destroy (helper); + return ret; +} + + +/* end of test_helper_rsa.c */ diff --git a/src/util/test_helper_rsa.conf b/src/util/test_helper_rsa.conf new file mode 100644 index 000000000..9880ae153 --- /dev/null +++ b/src/util/test_helper_rsa.conf @@ -0,0 +1,9 @@ +[coin_1] +duration_withdraw = 1 minute +rsa_keysize = 2048 + +[taler-helper-crypto-rsa] +lookahead_sign = 5 minutes +overlap_duration = 1 s +KEY_DIR = ${TALER_RUNTIME_DIR}/test_helper_rsa/ +UNIXPATH = ${TALER_RUNTIME_DIR}test_helper_rsa.unix |