X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Frevocation%2Frevocation_api.c;h=ebf85a94e32db5ad6e0fa6fa01d4c1c9586f70f2;hb=d0a9f269aa6575253b1c284d594a467e6fdeb7c7;hp=32fe995f762625d5996c45e2c5042ce362023907;hpb=0314e07406c3860c4dbc76b585000685f3437e09;p=oweals%2Fgnunet.git diff --git a/src/revocation/revocation_api.c b/src/revocation/revocation_api.c index 32fe995f7..ebf85a94e 100644 --- a/src/revocation/revocation_api.c +++ b/src/revocation/revocation_api.c @@ -27,6 +27,7 @@ #include "gnunet_signatures.h" #include "gnunet_protocols.h" #include "revocation.h" +#include /** @@ -39,7 +40,7 @@ struct GNUNET_REVOCATION_Query * Connection to the service. */ struct GNUNET_CLIENT_Connection *client; - + /** * Our configuration. */ @@ -59,9 +60,81 @@ struct GNUNET_REVOCATION_Query * Closure for @e func. */ void *func_cls; + + /** + * Transmission handle to the service. + */ + struct GNUNET_CLIENT_TransmitHandle *th; + }; +/** + * Handle response to our revocation query. + * + * @param cls our `struct GNUNET_REVOCATION_Query` handle + * @param msg response we got, NULL on disconnect + */ +static void +handle_revocation_query_response (void *cls, + const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_REVOCATION_Query *q = cls; + const struct QueryResponseMessage *qrm; + + if ( (NULL == msg) || + (sizeof (struct QueryResponseMessage) != ntohs (msg->size)) || + (GNUNET_MESSAGE_TYPE_REVOCATION_QUERY_RESPONSE != ntohs (msg->type)) ) + { + GNUNET_break (NULL == msg); + q->func (q->func_cls, GNUNET_SYSERR); + GNUNET_REVOCATION_query_cancel (q); + return; + } + qrm = (const struct QueryResponseMessage *) msg; + q->func (q->func_cls, ntohl (qrm->is_valid)); + GNUNET_REVOCATION_query_cancel (q); +} + + +/** + * Transmit our revocation query to the service. + * + * @param cls our `struct GNUNET_REVOCATION_Query` handle + * @param size number of bytes available in @a buf + * @param buf where to copy the query + * @return number of bytes copied to @a buf + */ +static size_t +send_revocation_query (void *cls, + size_t size, + void *buf) +{ + struct GNUNET_REVOCATION_Query *q = cls; + struct QueryMessage qm; + + q->th = NULL; + if ( (NULL == buf) || + (sizeof (struct QueryMessage) > size) ) + { + GNUNET_break (0); + q->func (q->func_cls, GNUNET_SYSERR); + GNUNET_REVOCATION_query_cancel (q); + return 0; + } + qm.header.size = htons (sizeof (struct QueryMessage)); + qm.header.type = htons (GNUNET_MESSAGE_TYPE_REVOCATION_QUERY); + qm.reserved = htonl (0); + qm.key = q->key; + memcpy (buf, &qm, sizeof (struct QueryMessage)); + GNUNET_CLIENT_receive (q->client, + &handle_revocation_query_response, + q, + GNUNET_TIME_UNIT_FOREVER_REL); + return sizeof (struct QueryMessage); +} + + /** * Check if a key was revoked. * @@ -80,11 +153,22 @@ GNUNET_REVOCATION_query (const struct GNUNET_CONFIGURATION_Handle *cfg, q = GNUNET_new (struct GNUNET_REVOCATION_Query); q->client = GNUNET_CLIENT_connect ("revocation", cfg); + if (NULL == q->client) + { + GNUNET_break (0); + GNUNET_free (q); + return NULL; + } q->cfg = cfg; q->key = *key; q->func = func; q->func_cls = func_cls; - GNUNET_break (0); + q->th = GNUNET_CLIENT_notify_transmit_ready (q->client, + sizeof (struct QueryMessage), + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_YES, + &send_revocation_query, + q); return q; } @@ -97,6 +181,11 @@ GNUNET_REVOCATION_query (const struct GNUNET_CONFIGURATION_Handle *cfg, void GNUNET_REVOCATION_query_cancel (struct GNUNET_REVOCATION_Query *q) { + if (NULL != q->th) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (q->th); + q->th = NULL; + } GNUNET_CLIENT_disconnect (q->client); GNUNET_free (q); } @@ -107,12 +196,12 @@ GNUNET_REVOCATION_query_cancel (struct GNUNET_REVOCATION_Query *q) */ struct GNUNET_REVOCATION_Handle { - + /** * Connection to the service. */ struct GNUNET_CLIENT_Connection *client; - + /** * Our configuration. */ @@ -143,9 +232,86 @@ struct GNUNET_REVOCATION_Handle */ void *func_cls; + /** + * Transmission handle to the service. + */ + struct GNUNET_CLIENT_TransmitHandle *th; + }; +/** + * Handle response to our revocation query. + * + * @param cls our `struct GNUNET_REVOCATION_Handle` handle + * @param msg response we got, NULL on disconnect + */ +static void +handle_revocation_response (void *cls, + const struct GNUNET_MessageHeader *msg) +{ + struct GNUNET_REVOCATION_Handle *h = cls; + const struct RevocationResponseMessage *rrm; + + if ( (NULL == msg) || + (sizeof (struct RevocationResponseMessage) != ntohs (msg->size)) || + (GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE_RESPONSE != ntohs (msg->type)) ) + { + GNUNET_break (NULL == msg); + h->func (h->func_cls, GNUNET_SYSERR); + GNUNET_REVOCATION_revoke_cancel (h); + return; + } + rrm = (const struct RevocationResponseMessage *) msg; + h->func (h->func_cls, ntohl (rrm->is_valid)); + GNUNET_REVOCATION_revoke_cancel (h); + +} + + +/** + * Transmit our revocation to the service. + * + * @param cls our `struct GNUNET_REVOCATION_Handle` handle + * @param size number of bytes available in @a buf + * @param buf where to copy the query + * @return number of bytes copied to @a buf + */ +static size_t +send_revoke (void *cls, + size_t size, + void *buf) +{ + struct GNUNET_REVOCATION_Handle *h = cls; + struct RevokeMessage rm; + + h->th = NULL; + if ( (NULL == buf) || + (sizeof (struct RevokeMessage) > size) ) + { + GNUNET_break (0); + h->func (h->func_cls, GNUNET_SYSERR); + GNUNET_REVOCATION_revoke_cancel (h); + return 0; + } + rm.header.size = htons (sizeof (struct RevokeMessage)); + rm.header.type = htons (GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE); + rm.reserved = htonl (0); + rm.proof_of_work = h->pow; + rm.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_REVOCATION); + rm.purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + + sizeof (struct GNUNET_CRYPTO_EccPublicSignKey)); + rm.public_key = h->key; + rm.signature = h->sig; + memcpy (buf, &rm, sizeof (struct RevokeMessage)); + GNUNET_CLIENT_receive (h->client, + &handle_revocation_response, + h, + GNUNET_TIME_UNIT_FOREVER_REL); + return sizeof (struct RevokeMessage); +} + + /** * Perform key revocation. * @@ -159,7 +325,7 @@ struct GNUNET_REVOCATION_Handle * (called with `is_valid` being #GNUNET_NO if * the revocation worked). * @param func_cls closure to pass to @a func - * @return handle to use in #GNUNET_REVOCATION_cancel to stop REVOCATION from invoking the callback + * @return handle to use in #GNUNET_REVOCATION_revoke_cancel to stop REVOCATION from invoking the callback */ struct GNUNET_REVOCATION_Handle * GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg, @@ -169,7 +335,20 @@ GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_REVOCATION_Callback func, void *func_cls) { struct GNUNET_REVOCATION_Handle *h; - + unsigned long long matching_bits; + + if ( (GNUNET_OK == + GNUNET_CONFIGURATION_get_value_number (cfg, + "REVOCATION", + "WORKBITS", + &matching_bits)) && + (GNUNET_YES != + GNUNET_REVOCATION_check_pow (key, pow, + (unsigned int) matching_bits)) ) + { + GNUNET_break (0); + return NULL; + } h = GNUNET_new (struct GNUNET_REVOCATION_Handle); h->client = GNUNET_CLIENT_connect ("revocation", cfg); h->cfg = cfg; @@ -178,7 +357,12 @@ GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg, h->pow = pow; h->func = func; h->func_cls = func_cls; - GNUNET_break (0); + h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, + sizeof (struct RevokeMessage), + GNUNET_TIME_UNIT_FOREVER_REL, + GNUNET_YES, + &send_revoke, + h); return h; } @@ -191,25 +375,82 @@ GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg, void GNUNET_REVOCATION_revoke_cancel (struct GNUNET_REVOCATION_Handle *h) { + if (NULL != h->th) + { + GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); + h->th = NULL; + } GNUNET_CLIENT_disconnect (h->client); GNUNET_free (h); } + +/** + * Calculate the 'proof-of-work' hash (an expensive hash). + * + * @param buf data to hash + * @param buf_len number of bytes in @a buf + * @param result where to write the resulting hash + */ +static void +pow_hash (const void *buf, + size_t buf_len, + struct GNUNET_HashCode *result) +{ + GNUNET_break (0 == + gcry_kdf_derive (buf, buf_len, + GCRY_KDF_SCRYPT, + 1 /* subalgo */, + "gnunet-revocation-proof-of-work", + strlen ("gnunet-revocation-proof-of-work"), + 2 /* iterations; keep cost of individual op small */, + sizeof (struct GNUNET_HashCode), result)); +} + + +/** + * Count the leading zeroes in hash. + * + * @param hash to count leading zeros in + * @return the number of leading zero bits. + */ +static unsigned int +count_leading_zeroes (const struct GNUNET_HashCode *hash) +{ + unsigned int hash_count; + + hash_count = 0; + while ((0 == GNUNET_CRYPTO_hash_get_bit (hash, hash_count))) + hash_count++; + return hash_count; +} + + /** * Check if the given proof-of-work value * would be acceptable for revoking the given key. * * @param key key to check for * @param pow proof of work value + * @param matching_bits how many bits must match (configuration) * @return #GNUNET_YES if the @a pow is acceptable, #GNUNET_NO if not */ int GNUNET_REVOCATION_check_pow (const struct GNUNET_CRYPTO_EccPublicSignKey *key, - uint64_t pow) + uint64_t pow, + unsigned int matching_bits) { - GNUNET_break (0); - return GNUNET_NO; + char buf[sizeof (struct GNUNET_CRYPTO_EccPublicSignKey) + + sizeof (pow)] GNUNET_ALIGN; + struct GNUNET_HashCode result; + + memcpy (buf, &pow, sizeof (pow)); + memcpy (&buf[sizeof (pow)], key, + sizeof (struct GNUNET_CRYPTO_EccPublicSignKey)); + pow_hash (buf, sizeof (buf), &result); + return (count_leading_zeroes (&result) >= + matching_bits) ? GNUNET_YES : GNUNET_NO; } @@ -223,7 +464,7 @@ void GNUNET_REVOCATION_sign_revocation (const struct GNUNET_CRYPTO_EccPrivateKey *key, struct GNUNET_CRYPTO_EccSignature *sig) { - struct GNUNET_REVOCATION_RevokeMessage rm; + struct RevokeMessage rm; rm.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_REVOCATION); rm.purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +