diff options
Diffstat (limited to 'src/service/revocation/revocation_api.c')
-rw-r--r-- | src/service/revocation/revocation_api.c | 440 |
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 | */ | ||
58 | struct 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 | */ | ||
76 | struct 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 | |||
106 | static 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 | */ |
302 | struct GNUNET_REVOCATION_Handle * | 248 | struct GNUNET_REVOCATION_Handle * |
303 | GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg, | 249 | GNUNET_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 | */ | ||
394 | static unsigned int | ||
395 | calculate_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 | |||
405 | struct GNUNET_REVOCATION_SignaturePurposePS * | ||
406 | REV_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 | |||
425 | enum GNUNET_GenericReturnValue | ||
426 | check_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 | |||
448 | enum GNUNET_GenericReturnValue | ||
449 | check_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 | */ | ||
466 | enum GNUNET_GenericReturnValue | ||
467 | GNUNET_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 | |||
568 | enum GNUNET_GenericReturnValue | ||
569 | sign_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 | |||
600 | enum GNUNET_GenericReturnValue | ||
601 | sign_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 | */ | ||
618 | void | ||
619 | GNUNET_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 | |||
626 | struct GNUNET_REVOCATION_PowCalculationHandle* | ||
627 | GNUNET_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 | */ | ||
655 | static int | ||
656 | cmp_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 | */ | ||
672 | enum GNUNET_GenericReturnValue | ||
673 | GNUNET_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 | */ | ||
741 | void | ||
742 | GNUNET_REVOCATION_pow_stop (struct GNUNET_REVOCATION_PowCalculationHandle *pc) | ||
743 | { | ||
744 | GNUNET_free (pc); | ||
745 | } | ||
746 | |||
747 | |||
748 | size_t | ||
749 | GNUNET_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 */ |