aboutsummaryrefslogtreecommitdiff
path: root/src/service/revocation/revocation_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/revocation/revocation_api.c')
-rw-r--r--src/service/revocation/revocation_api.c440
1 files changed, 5 insertions, 435 deletions
diff --git a/src/service/revocation/revocation_api.c b/src/service/revocation/revocation_api.c
index 3b7d83710..0e3641af8 100644
--- a/src/service/revocation/revocation_api.c
+++ b/src/service/revocation/revocation_api.c
@@ -52,60 +52,6 @@ struct GNUNET_REVOCATION_Query
52 52
53 53
54/** 54/**
55 * Helper struct that holds a found pow nonce
56 * and the corresponding number of leading zeros.
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_PowP *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
106static struct GNUNET_CRYPTO_PowSalt salt = { "GnsRevocationPow" };
107
108/**
109 * Generic error handler, called with the appropriate 55 * Generic error handler, called with the appropriate
110 * error code and the same closure specified at the creation of 56 * error code and the same closure specified at the creation of
111 * the message queue. 57 * the message queue.
@@ -301,7 +247,7 @@ handle_revocation_response (void *cls,
301 */ 247 */
302struct GNUNET_REVOCATION_Handle * 248struct GNUNET_REVOCATION_Handle *
303GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg, 249GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg,
304 const struct GNUNET_REVOCATION_PowP *pow, 250 const struct GNUNET_GNSRECORD_PowP *pow,
305 GNUNET_REVOCATION_Callback func, 251 GNUNET_REVOCATION_Callback func,
306 void *func_cls) 252 void *func_cls)
307{ 253{
@@ -339,9 +285,9 @@ GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg,
339 GNUNET_free (h); 285 GNUNET_free (h);
340 return NULL; 286 return NULL;
341 } 287 }
342 if (GNUNET_YES != GNUNET_REVOCATION_check_pow (pow, 288 if (GNUNET_YES != GNUNET_GNSRECORD_check_pow (pow,
343 (unsigned int) matching_bits, 289 (unsigned int) matching_bits,
344 epoch_duration)) 290 epoch_duration))
345 { 291 {
346 GNUNET_break (0); 292 GNUNET_break (0);
347 GNUNET_free (h); 293 GNUNET_free (h);
@@ -361,7 +307,7 @@ GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg,
361 } 307 }
362 h->func = func; 308 h->func = func;
363 h->func_cls = func_cls; 309 h->func_cls = func_cls;
364 size_t extra_len = GNUNET_REVOCATION_proof_get_size (pow); 310 size_t extra_len = GNUNET_GNSRECORD_proof_get_size (pow);
365 env = GNUNET_MQ_msg_extra (rm, 311 env = GNUNET_MQ_msg_extra (rm,
366 extra_len, 312 extra_len,
367 GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE); 313 GNUNET_MESSAGE_TYPE_REVOCATION_REVOKE);
@@ -385,380 +331,4 @@ GNUNET_REVOCATION_revoke_cancel (struct GNUNET_REVOCATION_Handle *h)
385} 331}
386 332
387 333
388/**
389 * Calculate the average zeros in the pows.
390 *
391 * @param ph the PowHandle
392 * @return the average number of zeros.
393 */
394static unsigned int
395calculate_score (const struct GNUNET_REVOCATION_PowCalculationHandle *ph)
396{
397 double sum = 0.0;
398 for (unsigned int j = 0; j<POW_COUNT; j++)
399 sum += ph->best[j].bits;
400 double avg = sum / POW_COUNT;
401 return avg;
402}
403
404
405struct GNUNET_REVOCATION_SignaturePurposePS *
406REV_create_signature_message (const struct GNUNET_REVOCATION_PowP *pow)
407{
408 struct GNUNET_REVOCATION_SignaturePurposePS *spurp;
409 const struct GNUNET_CRYPTO_PublicKey *pk;
410 size_t ksize;
411
412 pk = (const struct GNUNET_CRYPTO_PublicKey *) &pow[1];
413 ksize = GNUNET_CRYPTO_public_key_get_length (pk);
414 spurp = GNUNET_malloc (sizeof (*spurp) + ksize);
415 spurp->timestamp = pow->timestamp;
416 spurp->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_REVOCATION);
417 spurp->purpose.size = htonl (sizeof(*spurp) + ksize);
418 GNUNET_CRYPTO_write_public_key_to_buffer (pk,
419 (char*) &spurp[1],
420 ksize);
421 return spurp;
422}
423
424
425enum GNUNET_GenericReturnValue
426check_signature_identity (const struct GNUNET_REVOCATION_PowP *pow,
427 const struct GNUNET_CRYPTO_PublicKey *key)
428{
429 struct GNUNET_REVOCATION_SignaturePurposePS *spurp;
430 unsigned char *sig;
431 size_t ksize;
432 int ret;
433
434 ksize = GNUNET_CRYPTO_public_key_get_length (key);
435 spurp = REV_create_signature_message (pow);
436 sig = ((unsigned char*) &pow[1] + ksize);
437 ret =
438 GNUNET_CRYPTO_signature_verify_raw_ (
439 GNUNET_SIGNATURE_PURPOSE_GNS_REVOCATION,
440 &spurp->purpose,
441 sig,
442 key);
443 GNUNET_free (spurp);
444 return ret == GNUNET_OK ? GNUNET_OK : GNUNET_SYSERR;
445}
446
447
448enum GNUNET_GenericReturnValue
449check_signature (const struct GNUNET_REVOCATION_PowP *pow)
450{
451 const struct GNUNET_CRYPTO_PublicKey *pk;
452
453 pk = (const struct GNUNET_CRYPTO_PublicKey *) &pow[1];
454 return check_signature_identity (pow, pk);
455}
456
457
458/**
459 * Check if the given proof-of-work is valid.
460 *
461 * @param pow proof of work
462 * @param difficulty how many bits must match (configuration) LSD0001: D
463 * @param epoch_duration length of single epoch in configuration
464 * @return #GNUNET_YES if the @a pow is acceptable, #GNUNET_NO if not
465 */
466enum GNUNET_GenericReturnValue
467GNUNET_REVOCATION_check_pow (const struct GNUNET_REVOCATION_PowP *pow,
468 unsigned int difficulty,
469 struct GNUNET_TIME_Relative epoch_duration)
470{
471 char buf[sizeof(struct GNUNET_CRYPTO_PublicKey)
472 + sizeof (struct GNUNET_TIME_AbsoluteNBO)
473 + sizeof (uint64_t)] GNUNET_ALIGN;
474 struct GNUNET_HashCode result;
475 struct GNUNET_TIME_Absolute ts;
476 struct GNUNET_TIME_Absolute exp;
477 struct GNUNET_TIME_Relative ttl;
478 struct GNUNET_TIME_Relative buffer;
479 /* LSD0001: D' */
480 unsigned int score = 0;
481 unsigned int tmp_score = 0;
482 unsigned int epochs;
483 uint64_t pow_val;
484 ssize_t pklen;
485 const struct GNUNET_CRYPTO_PublicKey *pk;
486
487 pk = (const struct GNUNET_CRYPTO_PublicKey *) &pow[1];
488
489 /**
490 * Check if signature valid
491 */
492 if (GNUNET_OK != check_signature (pow))
493 {
494 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
495 "Proof of work signature invalid!\n");
496 return GNUNET_SYSERR;
497 }
498
499 /**
500 * First, check if PoW set is strictly monotically increasing
501 */
502 for (unsigned int i = 0; i < POW_COUNT - 1; i++)
503 {
504 if (GNUNET_ntohll (pow->pow[i]) >= GNUNET_ntohll (pow->pow[i + 1]))
505 return GNUNET_NO;
506 }
507 GNUNET_memcpy (&buf[sizeof(uint64_t)],
508 &pow->timestamp,
509 sizeof (uint64_t));
510 pklen = GNUNET_CRYPTO_public_key_get_length (pk);
511 if (0 > pklen)
512 {
513 GNUNET_break (0);
514 return GNUNET_NO;
515 }
516 GNUNET_memcpy (&buf[sizeof(uint64_t) * 2],
517 pk,
518 pklen);
519 for (unsigned int i = 0; i < POW_COUNT; i++)
520 {
521 pow_val = GNUNET_ntohll (pow->pow[i]);
522 GNUNET_memcpy (buf, &pow->pow[i], sizeof(uint64_t));
523 GNUNET_CRYPTO_pow_hash (&salt,
524 buf,
525 sizeof(buf),
526 &result);
527 tmp_score = GNUNET_CRYPTO_hash_count_leading_zeros (&result);
528 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
529 "Score %u with %" PRIu64 " (#%u)\n",
530 tmp_score, pow_val, i);
531
532 score += tmp_score;
533
534 }
535 score = score / POW_COUNT;
536 if (score < difficulty)
537 return GNUNET_NO;
538 /* LSD0001: (D'-D+1) */
539 epochs = score - difficulty + 1;
540
541 /**
542 * Check expiration
543 */
544 ts = GNUNET_TIME_absolute_ntoh (pow->timestamp);
545 ttl = GNUNET_TIME_relative_multiply (epoch_duration,
546 epochs);
547 /**
548 * Extend by 10% for unsynchronized clocks
549 */
550 buffer = GNUNET_TIME_relative_divide (epoch_duration,
551 10);
552 exp = GNUNET_TIME_absolute_add (ts, ttl);
553 exp = GNUNET_TIME_absolute_add (exp,
554 buffer);
555
556 if (0 != GNUNET_TIME_absolute_get_remaining (ts).rel_value_us)
557 return GNUNET_NO; /* Not yet valid. */
558 /* Revert to actual start time */
559 ts = GNUNET_TIME_absolute_add (ts,
560 buffer);
561
562 if (0 == GNUNET_TIME_absolute_get_remaining (exp).rel_value_us)
563 return GNUNET_NO; /* expired */
564 return GNUNET_YES;
565}
566
567
568enum GNUNET_GenericReturnValue
569sign_pow_identity (const struct GNUNET_CRYPTO_PrivateKey *key,
570 struct GNUNET_REVOCATION_PowP *pow)
571{
572 struct GNUNET_TIME_Absolute ts = GNUNET_TIME_absolute_get ();
573 struct GNUNET_REVOCATION_SignaturePurposePS *rp;
574 const struct GNUNET_CRYPTO_PublicKey *pk;
575 size_t ksize;
576 char *sig;
577
578 /**
579 * Predate the validity period to prevent rejections due to
580 * unsynchronized clocks
581 */
582 ts = GNUNET_TIME_absolute_subtract (ts,
583 GNUNET_TIME_UNIT_WEEKS);
584 pk = (const struct GNUNET_CRYPTO_PublicKey *) &pow[1];
585 ksize = GNUNET_CRYPTO_public_key_get_length (pk);
586 pow->timestamp = GNUNET_TIME_absolute_hton (ts);
587 rp = REV_create_signature_message (pow);
588 sig = ((char*) &pow[1]) + ksize;
589 int result = GNUNET_CRYPTO_sign_raw_ (key,
590 &rp->purpose,
591 (void*) sig);
592 GNUNET_free (rp);
593 if (result == GNUNET_SYSERR)
594 return GNUNET_NO;
595 else
596 return result;
597}
598
599
600enum GNUNET_GenericReturnValue
601sign_pow (const struct GNUNET_CRYPTO_PrivateKey *key,
602 struct GNUNET_REVOCATION_PowP *pow)
603{
604 struct GNUNET_CRYPTO_PublicKey *pk;
605
606 pk = (struct GNUNET_CRYPTO_PublicKey *) &pow[1];
607 GNUNET_CRYPTO_key_get_public (key, pk);
608 return sign_pow_identity (key, pow);
609}
610
611
612/**
613 * Initializes a fresh PoW computation.
614 *
615 * @param key the key to calculate the PoW for.
616 * @param[out] pow starting point for PoW calculation (not yet valid)
617 */
618void
619GNUNET_REVOCATION_pow_init (const struct GNUNET_CRYPTO_PrivateKey *key,
620 struct GNUNET_REVOCATION_PowP *pow)
621{
622 GNUNET_assert (GNUNET_OK == sign_pow (key, pow));
623}
624
625
626struct GNUNET_REVOCATION_PowCalculationHandle*
627GNUNET_REVOCATION_pow_start (struct GNUNET_REVOCATION_PowP *pow,
628 int epochs,
629 unsigned int difficulty)
630{
631 struct GNUNET_REVOCATION_PowCalculationHandle *pc;
632 struct GNUNET_TIME_Relative ttl;
633
634
635 pc = GNUNET_new (struct GNUNET_REVOCATION_PowCalculationHandle);
636 pc->pow = pow;
637 ttl = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_YEARS,
638 epochs);
639 pc->pow->ttl = GNUNET_TIME_relative_hton (ttl);
640 pc->current_pow = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
641 UINT64_MAX);
642 pc->difficulty = difficulty;
643 pc->epochs = epochs;
644 return pc;
645}
646
647
648/**
649 * Comparison function for quicksort
650 *
651 * @param a left element
652 * @param b right element
653 * @return a-b
654 */
655static int
656cmp_pow_value (const void *a, const void *b)
657{
658 return (GNUNET_ntohll (*(uint64_t*) a) - GNUNET_ntohll (*(uint64_t*) b));
659}
660
661
662/**
663 * Calculate a key revocation valid for broadcasting for a number
664 * of epochs.
665 *
666 * @param pc handle to the PoW, initially called with NULL.
667 * @param epochs number of epochs for which the revocation must be valid.
668 * @param pow current pow value to try
669 * @param difficulty current base difficulty to achieve
670 * @return #GNUNET_YES if the @a pow is acceptable, #GNUNET_NO if not
671 */
672enum GNUNET_GenericReturnValue
673GNUNET_REVOCATION_pow_round (struct GNUNET_REVOCATION_PowCalculationHandle *pc)
674{
675 char buf[sizeof(struct GNUNET_CRYPTO_PublicKey)
676 + sizeof (uint64_t)
677 + sizeof (uint64_t)] GNUNET_ALIGN;
678 struct GNUNET_HashCode result;
679 const struct GNUNET_CRYPTO_PublicKey *pk;
680 unsigned int zeros;
681 int ret;
682 uint64_t pow_nbo;
683 ssize_t ksize;
684
685 pc->current_pow++;
686 pk = (const struct GNUNET_CRYPTO_PublicKey *) &(pc->pow[1]);
687
688 /**
689 * Do not try duplicates
690 */
691 for (unsigned int i = 0; i < POW_COUNT; i++)
692 if (pc->current_pow == pc->best[i].pow)
693 return GNUNET_NO;
694 pow_nbo = GNUNET_htonll (pc->current_pow);
695 GNUNET_memcpy (buf, &pow_nbo, sizeof(uint64_t));
696 GNUNET_memcpy (&buf[sizeof(uint64_t)],
697 &pc->pow->timestamp,
698 sizeof (uint64_t));
699 ksize = GNUNET_CRYPTO_public_key_get_length (pk);
700 GNUNET_assert (0 < ksize);
701 GNUNET_memcpy (&buf[sizeof(uint64_t) * 2],
702 pk,
703 ksize);
704 GNUNET_CRYPTO_pow_hash (&salt,
705 buf,
706 sizeof(buf),
707 &result);
708 zeros = GNUNET_CRYPTO_hash_count_leading_zeros (&result);
709 for (unsigned int i = 0; i < POW_COUNT; i++)
710 {
711 if (pc->best[i].bits < zeros)
712 {
713 pc->best[i].bits = zeros;
714 pc->best[i].pow = pc->current_pow;
715 pc->pow->pow[i] = pow_nbo;
716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
717 "New best score %u with %" PRIu64 " (#%u)\n",
718 zeros, pc->current_pow, i);
719
720 break;
721 }
722 }
723 ret = calculate_score (pc) >= pc->difficulty + pc->epochs ? GNUNET_YES :
724 GNUNET_NO;
725 if (GNUNET_YES == ret)
726 {
727 /* Sort POWs) */
728 qsort (pc->pow->pow, POW_COUNT, sizeof (uint64_t), &cmp_pow_value);
729 }
730 return ret;
731}
732
733
734/**
735 * Stop a PoW calculation
736 *
737 * @param pc the calculation to clean up
738 * @return #GNUNET_YES if pow valid, #GNUNET_NO if pow was set but is not
739 * valid
740 */
741void
742GNUNET_REVOCATION_pow_stop (struct GNUNET_REVOCATION_PowCalculationHandle *pc)
743{
744 GNUNET_free (pc);
745}
746
747
748size_t
749GNUNET_REVOCATION_proof_get_size (const struct GNUNET_REVOCATION_PowP *pow)
750{
751 size_t size;
752 size_t ksize;
753 const struct GNUNET_CRYPTO_PublicKey *pk;
754
755 size = sizeof (struct GNUNET_REVOCATION_PowP);
756 pk = (const struct GNUNET_CRYPTO_PublicKey *) &pow[1];
757 ksize = GNUNET_CRYPTO_public_key_get_length (pk);
758 size += ksize;
759 size += GNUNET_CRYPTO_signature_get_raw_length_by_type (pk->type);
760 return size;
761}
762
763
764/* end of revocation_api.c */ 334/* end of revocation_api.c */