#include "gnunet_signatures.h"
#include "gnunet_protocols.h"
#include "revocation.h"
+#include <gcrypt.h>
/**
* Connection to the service.
*/
struct GNUNET_CLIENT_Connection *client;
-
+
/**
* Our configuration.
*/
* 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.
*
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;
}
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);
}
*/
struct GNUNET_REVOCATION_Handle
{
-
+
/**
* Connection to the service.
*/
struct GNUNET_CLIENT_Connection *client;
-
+
/**
* Our configuration.
*/
*/
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.
*
* (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,
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;
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;
}
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;
}
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) +