aboutsummaryrefslogtreecommitdiff
path: root/src/revocation/revocation_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/revocation/revocation_api.c')
-rw-r--r--src/revocation/revocation_api.c360
1 files changed, 314 insertions, 46 deletions
diff --git a/src/revocation/revocation_api.c b/src/revocation/revocation_api.c
index 4755d4816..18a312ab8 100644
--- a/src/revocation/revocation_api.c
+++ b/src/revocation/revocation_api.c
@@ -27,8 +27,7 @@
27#include "gnunet_signatures.h" 27#include "gnunet_signatures.h"
28#include "gnunet_protocols.h" 28#include "gnunet_protocols.h"
29#include "revocation.h" 29#include "revocation.h"
30#include <gcrypt.h> 30#include <inttypes.h>
31
32 31
33/** 32/**
34 * Handle for the key revocation query. 33 * Handle for the key revocation query.
@@ -53,6 +52,58 @@ struct GNUNET_REVOCATION_Query
53 52
54 53
55/** 54/**
55 * Helper struct that holds a found pow nonce
56 * and the corresponding number of leading zeroes.
57 */
58struct BestPow
59{
60 /**
61 * PoW nonce
62 */
63 uint64_t pow;
64
65 /**
66 * Corresponding zero bits in hash
67 */
68 unsigned int bits;
69};
70
71
72/**
73 * The handle to a PoW calculation.
74 * Used in iterative PoW rounds.
75 */
76struct GNUNET_REVOCATION_PowCalculationHandle
77{
78 /**
79 * Current set of found PoWs
80 */
81 struct BestPow best[POW_COUNT];
82
83 /**
84 * The final PoW result data structure.
85 */
86 struct GNUNET_REVOCATION_Pow *pow;
87
88 /**
89 * The current nonce to try
90 */
91 uint64_t current_pow;
92
93 /**
94 * Epochs how long the PoW should be valid.
95 * This is added on top of the difficulty in the PoW.
96 */
97 unsigned int epochs;
98
99 /**
100 * The difficulty (leading zeros) to achieve.
101 */
102 unsigned int difficulty;
103
104};
105
106/**
56 * Generic error handler, called with the appropriate 107 * Generic error handler, called with the appropriate
57 * error code and the same closure specified at the creation of 108 * error code and the same closure specified at the creation of
58 * the message queue. 109 * the message queue.
@@ -235,6 +286,7 @@ handle_revocation_response (void *cls,
235 * @param key public key of the key to revoke 286 * @param key public key of the key to revoke
236 * @param sig signature to use on the revocation (should have been 287 * @param sig signature to use on the revocation (should have been
237 * created using #GNUNET_REVOCATION_sign_revocation). 288 * created using #GNUNET_REVOCATION_sign_revocation).
289 * @param ts revocation timestamp
238 * @param pow proof of work to use (should have been created by 290 * @param pow proof of work to use (should have been created by
239 * iteratively calling #GNUNET_REVOCATION_check_pow) 291 * iteratively calling #GNUNET_REVOCATION_check_pow)
240 * @param func funtion to call with the result of the check 292 * @param func funtion to call with the result of the check
@@ -245,9 +297,7 @@ handle_revocation_response (void *cls,
245 */ 297 */
246struct GNUNET_REVOCATION_Handle * 298struct GNUNET_REVOCATION_Handle *
247GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg, 299GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg,
248 const struct GNUNET_CRYPTO_EcdsaPublicKey *key, 300 const struct GNUNET_REVOCATION_Pow *pow,
249 const struct GNUNET_CRYPTO_EcdsaSignature *sig,
250 uint64_t pow,
251 GNUNET_REVOCATION_Callback func, 301 GNUNET_REVOCATION_Callback func,
252 void *func_cls) 302 void *func_cls)
253{ 303{
@@ -261,23 +311,39 @@ GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg,
261 GNUNET_MQ_handler_end () 311 GNUNET_MQ_handler_end ()
262 }; 312 };
263 unsigned long long matching_bits; 313 unsigned long long matching_bits;
314 struct GNUNET_TIME_Relative epoch_duration;
264 struct RevokeMessage *rm; 315 struct RevokeMessage *rm;
265 struct GNUNET_MQ_Envelope *env; 316 struct GNUNET_MQ_Envelope *env;
266 317
267 if ((GNUNET_OK == 318 if ((GNUNET_OK !=
268 GNUNET_CONFIGURATION_get_value_number (cfg, 319 GNUNET_CONFIGURATION_get_value_number (cfg,
269 "REVOCATION", 320 "REVOCATION",
270 "WORKBITS", 321 "WORKBITS",
271 &matching_bits)) && 322 &matching_bits)))
272 (GNUNET_YES != 323 {
273 GNUNET_REVOCATION_check_pow (key, 324 GNUNET_break (0);
274 pow, 325 GNUNET_free (h);
275 (unsigned int) matching_bits))) 326 return NULL;
327 }
328 if ((GNUNET_OK !=
329 GNUNET_CONFIGURATION_get_value_time (cfg,
330 "REVOCATION",
331 "EPOCH_DURATION",
332 &epoch_duration)))
276 { 333 {
277 GNUNET_break (0); 334 GNUNET_break (0);
278 GNUNET_free (h); 335 GNUNET_free (h);
279 return NULL; 336 return NULL;
280 } 337 }
338 if (GNUNET_YES != GNUNET_REVOCATION_check_pow (pow,
339 (unsigned int) matching_bits,
340 epoch_duration))
341 {
342 GNUNET_break (0);
343 GNUNET_free (h);
344 return NULL;
345 }
346
281 347
282 h->mq = GNUNET_CLIENT_connect (cfg, 348 h->mq = GNUNET_CLIENT_connect (cfg,
283 "revocation", 349 "revocation",
@@ -294,12 +360,7 @@ GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg,
294 env = GNUNET_MQ_msg (rm, 360 env = GNUNET_MQ_msg (rm,
295 GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE); 361 GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE);
296 rm->reserved = htonl (0); 362 rm->reserved = htonl (0);
297 rm->proof_of_work = pow; 363 rm->proof_of_work = *pow;
298 rm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_REVOCATION);
299 rm->purpose.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
300 + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey));
301 rm->public_key = *key;
302 rm->signature = *sig;
303 GNUNET_MQ_send (h->mq, 364 GNUNET_MQ_send (h->mq,
304 env); 365 env);
305 return h; 366 return h;
@@ -342,56 +403,263 @@ count_leading_zeroes (const struct GNUNET_HashCode *hash)
342 403
343 404
344/** 405/**
345 * Check if the given proof-of-work value 406 * Calculate the average zeros in the pows.
346 * would be acceptable for revoking the given key.
347 * 407 *
348 * @param key key to check for 408 * @param ph the PowHandle
349 * @param pow proof of work value 409 * @return the average number of zeroes.
410 */
411static unsigned int
412calculate_score (const struct GNUNET_REVOCATION_PowCalculationHandle *ph)
413{
414 double sum = 0.0;
415 for (unsigned int j = 0; j<POW_COUNT; j++)
416 sum += ph->best[j].bits;
417 double avg = sum / POW_COUNT;
418 return avg;
419}
420
421
422/**
423 * Check if the given proof-of-work is valid.
424 *
425 * @param pow proof of work
350 * @param matching_bits how many bits must match (configuration) 426 * @param matching_bits how many bits must match (configuration)
427 * @param epoch_duration length of single epoch in configuration
428 * @return #GNUNET_YES if the @a pow is acceptable, #GNUNET_NO if not
429 */
430enum GNUNET_GenericReturnValue
431GNUNET_REVOCATION_check_pow (const struct GNUNET_REVOCATION_Pow *pow,
432 unsigned int difficulty,
433 struct GNUNET_TIME_Relative epoch_duration)
434{
435 char buf[sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)
436 + sizeof (struct GNUNET_TIME_AbsoluteNBO)
437 + sizeof (uint64_t)] GNUNET_ALIGN;
438 struct GNUNET_REVOCATION_SignaturePurpose spurp;
439 struct GNUNET_HashCode result;
440 struct GNUNET_TIME_Absolute ts;
441 struct GNUNET_TIME_Absolute exp;
442 struct GNUNET_TIME_Relative ttl;
443 struct GNUNET_TIME_Relative buffer;
444 unsigned int score = 0;
445 unsigned int tmp_score = 0;
446 unsigned int epochs;
447 uint64_t pow_val;
448
449 /**
450 * Check if signature valid
451 */
452 spurp.key = pow->key;
453 spurp.timestamp = pow->timestamp;
454 spurp.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_REVOCATION);
455 spurp.purpose.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
456 + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)
457 + sizeof (struct GNUNET_TIME_AbsoluteNBO));
458 if (GNUNET_OK !=
459 GNUNET_CRYPTO_ecdsa_verify_ (GNUNET_SIGNATURE_PURPOSE_REVOCATION,
460 &spurp.purpose,
461 &pow->signature,
462 &pow->key))
463 {
464 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
465 "Proof of work signature invalid!\n");
466 return GNUNET_NO;
467 }
468
469 /**
470 * First, check if any duplicates are in the PoW set
471 */
472 for (unsigned int i = 0; i < POW_COUNT; i++)
473 {
474 for (unsigned int j = i + 1; j < POW_COUNT; j++)
475 {
476 if (pow->pow[i] == pow->pow[j])
477 return GNUNET_NO;
478 }
479 }
480 GNUNET_memcpy (&buf[sizeof(uint64_t)],
481 &pow->timestamp,
482 sizeof (uint64_t));
483 GNUNET_memcpy (&buf[sizeof(uint64_t) * 2],
484 &pow->key,
485 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey));
486 for (unsigned int i = 0; i < POW_COUNT; i++)
487 {
488 pow_val = GNUNET_ntohll (pow->pow[i]);
489 GNUNET_memcpy (buf, &pow_val, sizeof(uint64_t));
490 GNUNET_CRYPTO_pow_hash ("gnunet-revocation-proof-of-work",
491 buf,
492 sizeof(buf),
493 &result);
494 tmp_score = count_leading_zeroes (&result);
495 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
496 "Score %u with %" PRIu64 " (#%u)\n",
497 tmp_score, pow_val, i);
498 score += tmp_score;
499
500 }
501 score = score / POW_COUNT;
502 if (score < difficulty)
503 return GNUNET_NO;
504 epochs = score - difficulty;
505
506 /**
507 * Check expiration
508 */
509 ts = GNUNET_TIME_absolute_ntoh (pow->timestamp);
510 ttl = GNUNET_TIME_relative_multiply (epoch_duration,
511 epochs);
512 /**
513 * Extend by 10% for unsynchronized clocks
514 */
515 buffer = GNUNET_TIME_relative_divide (epoch_duration,
516 10);
517 exp = GNUNET_TIME_absolute_add (ts, ttl);
518 exp = GNUNET_TIME_absolute_add (exp,
519 buffer);
520
521 if (0 != GNUNET_TIME_absolute_get_remaining (ts).rel_value_us)
522 return GNUNET_NO; /* Not yet valid. */
523 /* Revert to actual start time */
524 ts = GNUNET_TIME_absolute_add (ts,
525 buffer);
526
527 if (0 == GNUNET_TIME_absolute_get_remaining (exp).rel_value_us)
528 return GNUNET_NO; /* expired */
529 return GNUNET_YES;
530}
531
532
533/**
534 * Initializes a fresh PoW computation.
535 *
536 * @param key the key to calculate the PoW for.
537 * @param[out] pow starting point for PoW calculation (not yet valid)
538 */
539void
540GNUNET_REVOCATION_pow_init (const struct GNUNET_CRYPTO_EcdsaPrivateKey *key,
541 struct GNUNET_REVOCATION_Pow *pow)
542{
543 struct GNUNET_TIME_Absolute ts = GNUNET_TIME_absolute_get ();
544 struct GNUNET_REVOCATION_SignaturePurpose rp;
545
546 /**
547 * Predate the validity period to prevent rejections due to
548 * unsynchronized clocks
549 */
550 ts = GNUNET_TIME_absolute_subtract (ts,
551 GNUNET_TIME_UNIT_WEEKS);
552
553 pow->timestamp = GNUNET_TIME_absolute_hton (ts);
554 rp.timestamp = pow->timestamp;
555 rp.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_REVOCATION);
556 rp.purpose.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
557 + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)
558 + sizeof (struct GNUNET_TIME_AbsoluteNBO));
559 GNUNET_CRYPTO_ecdsa_key_get_public (key, &pow->key);
560 rp.key = pow->key;
561 GNUNET_assert (GNUNET_OK ==
562 GNUNET_CRYPTO_ecdsa_sign_ (key,
563 &rp.purpose,
564 &pow->signature));
565}
566
567
568/**
569 * Starts a proof-of-work calculation given the pow object as well as
570 * target epochs and difficulty.
571 *
572 * @param pow the PoW to based calculations on.
573 * @param epochs the number of epochs for which the PoW must be valid.
574 * @param difficulty the base difficulty of the PoW.
575 * @return a handle for use in PoW rounds
576 */
577struct GNUNET_REVOCATION_PowCalculationHandle*
578GNUNET_REVOCATION_pow_start (struct GNUNET_REVOCATION_Pow *pow,
579 int epochs,
580 unsigned int difficulty)
581{
582 struct GNUNET_REVOCATION_PowCalculationHandle *pc;
583
584 pc = GNUNET_new (struct GNUNET_REVOCATION_PowCalculationHandle);
585 pc->pow = pow;
586 pc->current_pow = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
587 UINT64_MAX);
588 pc->difficulty = difficulty;
589 pc->epochs = epochs;
590 return pc;
591}
592
593
594/**
595 * Calculate a key revocation valid for broadcasting for a number
596 * of epochs.
597 *
598 * @param pc handle to the PoW, initially called with NULL.
599 * @param epochs number of epochs for which the revocation must be valid.
600 * @param pow current pow value to try
601 * @param difficulty current base difficulty to achieve
351 * @return #GNUNET_YES if the @a pow is acceptable, #GNUNET_NO if not 602 * @return #GNUNET_YES if the @a pow is acceptable, #GNUNET_NO if not
352 */ 603 */
353int 604enum GNUNET_GenericReturnValue
354GNUNET_REVOCATION_check_pow (const struct GNUNET_CRYPTO_EcdsaPublicKey *key, 605GNUNET_REVOCATION_pow_round (struct GNUNET_REVOCATION_PowCalculationHandle *pc)
355 uint64_t pow,
356 unsigned int matching_bits)
357{ 606{
358 char buf[sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey) 607 char buf[sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)
359 + sizeof(pow)] GNUNET_ALIGN; 608 + sizeof (uint64_t)
609 + sizeof (uint64_t)] GNUNET_ALIGN;
360 struct GNUNET_HashCode result; 610 struct GNUNET_HashCode result;
611 unsigned int zeros;
612
613 pc->current_pow++;
361 614
362 GNUNET_memcpy (buf, &pow, sizeof(pow)); 615 /**
363 GNUNET_memcpy (&buf[sizeof(pow)], key, 616 * Do not try duplicates
617 */
618 for (unsigned int i = 0; i < POW_COUNT; i++)
619 if (pc->current_pow == pc->best[i].pow)
620 return GNUNET_NO;
621
622 GNUNET_memcpy (buf, &pc->current_pow, sizeof(uint64_t));
623 GNUNET_memcpy (&buf[sizeof(uint64_t)],
624 &pc->pow->timestamp,
625 sizeof (uint64_t));
626 GNUNET_memcpy (&buf[sizeof(uint64_t) * 2],
627 &pc->pow->key,
364 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey)); 628 sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey));
365 GNUNET_CRYPTO_pow_hash ("gnunet-revocation-proof-of-work", 629 GNUNET_CRYPTO_pow_hash ("gnunet-revocation-proof-of-work",
366 buf, 630 buf,
367 sizeof(buf), 631 sizeof(buf),
368 &result); 632 &result);
369 return (count_leading_zeroes (&result) >= 633 zeros = count_leading_zeroes (&result);
370 matching_bits) ? GNUNET_YES : GNUNET_NO; 634 for (unsigned int i = 0; i < POW_COUNT; i++)
635 {
636 if (pc->best[i].bits < zeros)
637 {
638 pc->best[i].bits = zeros;
639 pc->best[i].pow = pc->current_pow;
640 pc->pow->pow[i] = GNUNET_htonll (pc->current_pow);
641 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
642 "New best score %u with %" PRIu64 " (#%u)\n",
643 zeros, pc->current_pow, i);
644 break;
645 }
646 }
647 return calculate_score (pc) >= pc->difficulty + pc->epochs ? GNUNET_YES :
648 GNUNET_NO;
371} 649}
372 650
373 651
374/** 652/**
375 * Create a revocation signature. 653 * Stop a PoW calculation
376 * 654 *
377 * @param key private key of the key to revoke 655 * @param pc the calculation to clean up
378 * @param sig where to write the revocation signature 656 * @return #GNUNET_YES if pow valid, #GNUNET_NO if pow was set but is not
657 * valid
379 */ 658 */
380void 659void
381GNUNET_REVOCATION_sign_revocation (const struct 660GNUNET_REVOCATION_pow_stop (struct GNUNET_REVOCATION_PowCalculationHandle *pc)
382 GNUNET_CRYPTO_EcdsaPrivateKey *key,
383 struct GNUNET_CRYPTO_EcdsaSignature *sig)
384{ 661{
385 struct RevokeMessage rm; 662 GNUNET_free (pc);
386
387 rm.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_REVOCATION);
388 rm.purpose.size = htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
389 + sizeof(struct GNUNET_CRYPTO_EcdsaPublicKey));
390 GNUNET_CRYPTO_ecdsa_key_get_public (key, &rm.public_key);
391 GNUNET_assert (GNUNET_OK ==
392 GNUNET_CRYPTO_ecdsa_sign_ (key,
393 &rm.purpose,
394 sig));
395} 663}
396 664
397 665