diff options
Diffstat (limited to 'src/revocation/revocation_api.c')
-rw-r--r-- | src/revocation/revocation_api.c | 360 |
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 | */ | ||
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_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 | */ |
246 | struct GNUNET_REVOCATION_Handle * | 298 | struct GNUNET_REVOCATION_Handle * |
247 | GNUNET_REVOCATION_revoke (const struct GNUNET_CONFIGURATION_Handle *cfg, | 299 | GNUNET_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 | */ | ||
411 | static unsigned int | ||
412 | calculate_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 | */ | ||
430 | enum GNUNET_GenericReturnValue | ||
431 | GNUNET_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 | */ | ||
539 | void | ||
540 | GNUNET_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 | */ | ||
577 | struct GNUNET_REVOCATION_PowCalculationHandle* | ||
578 | GNUNET_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 | */ |
353 | int | 604 | enum GNUNET_GenericReturnValue |
354 | GNUNET_REVOCATION_check_pow (const struct GNUNET_CRYPTO_EcdsaPublicKey *key, | 605 | GNUNET_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 | */ |
380 | void | 659 | void |
381 | GNUNET_REVOCATION_sign_revocation (const struct | 660 | GNUNET_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 | ||