diff options
author | Christian Grothoff <christian@grothoff.org> | 2021-08-27 17:44:01 +0200 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2021-08-27 17:44:01 +0200 |
commit | 2e2a558a59d0e7a25953cddf2afb67b7ab96135c (patch) | |
tree | a8bbc38cdb83092cea3624a855d63a5fb8a71603 | |
parent | 3a6466bb3854863b4b35deb08cb2e4ed03ebf12b (diff) | |
download | anastasis-2e2a558a59d0e7a25953cddf2afb67b7ab96135c.tar.gz anastasis-2e2a558a59d0e7a25953cddf2afb67b7ab96135c.zip |
fix retry counter logic, deal with negative retry counters, limit code reuse for iban method
-rw-r--r-- | src/authorization/anastasis_authorization_plugin_email.c | 5 | ||||
-rw-r--r-- | src/authorization/anastasis_authorization_plugin_file.c | 6 | ||||
-rw-r--r-- | src/authorization/anastasis_authorization_plugin_iban.c | 1 | ||||
-rw-r--r-- | src/authorization/anastasis_authorization_plugin_post.c | 7 | ||||
-rw-r--r-- | src/authorization/anastasis_authorization_plugin_sms.c | 5 | ||||
-rw-r--r-- | src/backend/anastasis-httpd_truth.c | 56 | ||||
-rw-r--r-- | src/include/anastasis_authorization_plugin.h | 6 | ||||
-rw-r--r-- | src/include/anastasis_database_plugin.h | 30 | ||||
-rw-r--r-- | src/reducer/anastasis_api_recovery_redux.c | 1 | ||||
-rw-r--r-- | src/restclient/anastasis_api_keyshare_lookup.c | 4 | ||||
-rw-r--r-- | src/stasis/plugin_anastasis_postgres.c | 154 | ||||
-rw-r--r-- | src/stasis/test_anastasis_db.c | 3 |
12 files changed, 82 insertions, 196 deletions
diff --git a/src/authorization/anastasis_authorization_plugin_email.c b/src/authorization/anastasis_authorization_plugin_email.c index 78c12ca..0eefcc5 100644 --- a/src/authorization/anastasis_authorization_plugin_email.c +++ b/src/authorization/anastasis_authorization_plugin_email.c | |||
@@ -27,6 +27,10 @@ | |||
27 | #include <gnunet/gnunet_db_lib.h> | 27 | #include <gnunet/gnunet_db_lib.h> |
28 | #include "anastasis_database_lib.h" | 28 | #include "anastasis_database_lib.h" |
29 | 29 | ||
30 | /** | ||
31 | * How many retries do we allow per code? | ||
32 | */ | ||
33 | #define INITIAL_RETRY_COUNTER 3 | ||
30 | 34 | ||
31 | /** | 35 | /** |
32 | * Saves the State of a authorization plugin. | 36 | * Saves the State of a authorization plugin. |
@@ -595,6 +599,7 @@ libanastasis_plugin_authorization_email_init (void *cls) | |||
595 | } | 599 | } |
596 | 600 | ||
597 | plugin = GNUNET_new (struct ANASTASIS_AuthorizationPlugin); | 601 | plugin = GNUNET_new (struct ANASTASIS_AuthorizationPlugin); |
602 | plugin->retry_counter = INITIAL_RETRY_COUNTER; | ||
598 | plugin->code_validity_period = GNUNET_TIME_UNIT_DAYS; | 603 | plugin->code_validity_period = GNUNET_TIME_UNIT_DAYS; |
599 | plugin->code_rotation_period = GNUNET_TIME_UNIT_HOURS; | 604 | plugin->code_rotation_period = GNUNET_TIME_UNIT_HOURS; |
600 | plugin->code_retransmission_frequency = GNUNET_TIME_UNIT_MINUTES; | 605 | plugin->code_retransmission_frequency = GNUNET_TIME_UNIT_MINUTES; |
diff --git a/src/authorization/anastasis_authorization_plugin_file.c b/src/authorization/anastasis_authorization_plugin_file.c index db9dc67..66dbbe1 100644 --- a/src/authorization/anastasis_authorization_plugin_file.c +++ b/src/authorization/anastasis_authorization_plugin_file.c | |||
@@ -24,6 +24,11 @@ | |||
24 | #include <gnunet/gnunet_db_lib.h> | 24 | #include <gnunet/gnunet_db_lib.h> |
25 | #include "anastasis_database_lib.h" | 25 | #include "anastasis_database_lib.h" |
26 | 26 | ||
27 | /** | ||
28 | * How many retries do we allow per code? | ||
29 | */ | ||
30 | #define INITIAL_RETRY_COUNTER 3 | ||
31 | |||
27 | 32 | ||
28 | /** | 33 | /** |
29 | * Saves the state of a authorization process | 34 | * Saves the state of a authorization process |
@@ -293,6 +298,7 @@ libanastasis_plugin_authorization_file_init (void *cls) | |||
293 | 298 | ||
294 | plugin = GNUNET_new (struct ANASTASIS_AuthorizationPlugin); | 299 | plugin = GNUNET_new (struct ANASTASIS_AuthorizationPlugin); |
295 | plugin->cls = (void *) ac; | 300 | plugin->cls = (void *) ac; |
301 | plugin->retry_counter = INITIAL_RETRY_COUNTER; | ||
296 | plugin->code_validity_period = GNUNET_TIME_UNIT_MINUTES; | 302 | plugin->code_validity_period = GNUNET_TIME_UNIT_MINUTES; |
297 | plugin->code_rotation_period = GNUNET_TIME_UNIT_MINUTES; | 303 | plugin->code_rotation_period = GNUNET_TIME_UNIT_MINUTES; |
298 | plugin->code_retransmission_frequency = GNUNET_TIME_UNIT_MINUTES; | 304 | plugin->code_retransmission_frequency = GNUNET_TIME_UNIT_MINUTES; |
diff --git a/src/authorization/anastasis_authorization_plugin_iban.c b/src/authorization/anastasis_authorization_plugin_iban.c index be8f33b..cdd51a7 100644 --- a/src/authorization/anastasis_authorization_plugin_iban.c +++ b/src/authorization/anastasis_authorization_plugin_iban.c | |||
@@ -697,6 +697,7 @@ libanastasis_plugin_authorization_iban_init (void *cls) | |||
697 | ctx->ac = ac; | 697 | ctx->ac = ac; |
698 | plugin = GNUNET_new (struct ANASTASIS_AuthorizationPlugin); | 698 | plugin = GNUNET_new (struct ANASTASIS_AuthorizationPlugin); |
699 | plugin->payment_plugin_managed = true; | 699 | plugin->payment_plugin_managed = true; |
700 | plugin->retry_counter = UINT32_MAX; /* long polling */ | ||
700 | plugin->code_validity_period = CODE_VALIDITY_PERIOD; | 701 | plugin->code_validity_period = CODE_VALIDITY_PERIOD; |
701 | plugin->code_rotation_period = GNUNET_TIME_UNIT_ZERO; | 702 | plugin->code_rotation_period = GNUNET_TIME_UNIT_ZERO; |
702 | plugin->code_retransmission_frequency = GNUNET_TIME_UNIT_ZERO; /* not applicable */ | 703 | plugin->code_retransmission_frequency = GNUNET_TIME_UNIT_ZERO; /* not applicable */ |
diff --git a/src/authorization/anastasis_authorization_plugin_post.c b/src/authorization/anastasis_authorization_plugin_post.c index 98dd042..4adeffd 100644 --- a/src/authorization/anastasis_authorization_plugin_post.c +++ b/src/authorization/anastasis_authorization_plugin_post.c | |||
@@ -28,6 +28,12 @@ | |||
28 | #include "anastasis_database_lib.h" | 28 | #include "anastasis_database_lib.h" |
29 | 29 | ||
30 | /** | 30 | /** |
31 | * How many retries do we allow per code? | ||
32 | */ | ||
33 | #define INITIAL_RETRY_COUNTER 3 | ||
34 | |||
35 | |||
36 | /** | ||
31 | * Saves the State of a authorization plugin. | 37 | * Saves the State of a authorization plugin. |
32 | */ | 38 | */ |
33 | struct PostContext | 39 | struct PostContext |
@@ -633,6 +639,7 @@ libanastasis_plugin_authorization_post_init (void *cls) | |||
633 | GNUNET_free (fn); | 639 | GNUNET_free (fn); |
634 | } | 640 | } |
635 | plugin = GNUNET_new (struct ANASTASIS_AuthorizationPlugin); | 641 | plugin = GNUNET_new (struct ANASTASIS_AuthorizationPlugin); |
642 | plugin->retry_counter = INITIAL_RETRY_COUNTER; | ||
636 | plugin->code_validity_period = GNUNET_TIME_UNIT_MONTHS; | 643 | plugin->code_validity_period = GNUNET_TIME_UNIT_MONTHS; |
637 | plugin->code_rotation_period = GNUNET_TIME_UNIT_WEEKS; | 644 | plugin->code_rotation_period = GNUNET_TIME_UNIT_WEEKS; |
638 | plugin->code_retransmission_frequency | 645 | plugin->code_retransmission_frequency |
diff --git a/src/authorization/anastasis_authorization_plugin_sms.c b/src/authorization/anastasis_authorization_plugin_sms.c index 4922380..94b2c0d 100644 --- a/src/authorization/anastasis_authorization_plugin_sms.c +++ b/src/authorization/anastasis_authorization_plugin_sms.c | |||
@@ -27,6 +27,10 @@ | |||
27 | #include <gnunet/gnunet_db_lib.h> | 27 | #include <gnunet/gnunet_db_lib.h> |
28 | #include "anastasis_database_lib.h" | 28 | #include "anastasis_database_lib.h" |
29 | 29 | ||
30 | /** | ||
31 | * How many retries do we allow per code? | ||
32 | */ | ||
33 | #define INITIAL_RETRY_COUNTER 3 | ||
30 | 34 | ||
31 | /** | 35 | /** |
32 | * Saves the State of a authorization plugin. | 36 | * Saves the State of a authorization plugin. |
@@ -585,6 +589,7 @@ libanastasis_plugin_authorization_sms_init (void *cls) | |||
585 | } | 589 | } |
586 | } | 590 | } |
587 | plugin = GNUNET_new (struct ANASTASIS_AuthorizationPlugin); | 591 | plugin = GNUNET_new (struct ANASTASIS_AuthorizationPlugin); |
592 | plugin->retry_counter = INITIAL_RETRY_COUNTER; | ||
588 | plugin->code_validity_period = GNUNET_TIME_UNIT_DAYS; | 593 | plugin->code_validity_period = GNUNET_TIME_UNIT_DAYS; |
589 | plugin->code_rotation_period = GNUNET_TIME_UNIT_HOURS; | 594 | plugin->code_rotation_period = GNUNET_TIME_UNIT_HOURS; |
590 | plugin->code_retransmission_frequency = GNUNET_TIME_UNIT_MINUTES; | 595 | plugin->code_retransmission_frequency = GNUNET_TIME_UNIT_MINUTES; |
diff --git a/src/backend/anastasis-httpd_truth.c b/src/backend/anastasis-httpd_truth.c index df105dd..613e27f 100644 --- a/src/backend/anastasis-httpd_truth.c +++ b/src/backend/anastasis-httpd_truth.c | |||
@@ -56,6 +56,7 @@ | |||
56 | */ | 56 | */ |
57 | #define INITIAL_RETRY_COUNTER 3 | 57 | #define INITIAL_RETRY_COUNTER 3 |
58 | 58 | ||
59 | |||
59 | struct GetContext | 60 | struct GetContext |
60 | { | 61 | { |
61 | 62 | ||
@@ -1289,6 +1290,8 @@ AH_handler_truth_get ( | |||
1289 | but check that the hash matches */ | 1290 | but check that the hash matches */ |
1290 | if (is_question) | 1291 | if (is_question) |
1291 | { | 1292 | { |
1293 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1294 | "Handling security question challenge\n"); | ||
1292 | if (! gc->have_response) | 1295 | if (! gc->have_response) |
1293 | { | 1296 | { |
1294 | GNUNET_free (decrypted_truth); | 1297 | GNUNET_free (decrypted_truth); |
@@ -1306,6 +1309,7 @@ AH_handler_truth_get ( | |||
1306 | enum ANASTASIS_DB_CodeStatus cs; | 1309 | enum ANASTASIS_DB_CodeStatus cs; |
1307 | struct GNUNET_HashCode hc; | 1310 | struct GNUNET_HashCode hc; |
1308 | bool satisfied; | 1311 | bool satisfied; |
1312 | uint64_t dummy; | ||
1309 | 1313 | ||
1310 | rt = GNUNET_TIME_UNIT_FOREVER_ABS; | 1314 | rt = GNUNET_TIME_UNIT_FOREVER_ABS; |
1311 | qs = db->create_challenge_code (db->cls, | 1315 | qs = db->create_challenge_code (db->cls, |
@@ -1340,6 +1344,7 @@ AH_handler_truth_get ( | |||
1340 | cs = db->verify_challenge_code (db->cls, | 1344 | cs = db->verify_challenge_code (db->cls, |
1341 | &gc->truth_uuid, | 1345 | &gc->truth_uuid, |
1342 | &hc, | 1346 | &hc, |
1347 | &dummy, | ||
1343 | &satisfied); | 1348 | &satisfied); |
1344 | switch (cs) | 1349 | switch (cs) |
1345 | { | 1350 | { |
@@ -1390,11 +1395,13 @@ AH_handler_truth_get ( | |||
1390 | { | 1395 | { |
1391 | enum ANASTASIS_DB_CodeStatus cs; | 1396 | enum ANASTASIS_DB_CodeStatus cs; |
1392 | bool satisfied; | 1397 | bool satisfied; |
1398 | uint64_t code; | ||
1393 | 1399 | ||
1394 | GNUNET_free (truth_mime); | 1400 | GNUNET_free (truth_mime); |
1395 | cs = db->verify_challenge_code (db->cls, | 1401 | cs = db->verify_challenge_code (db->cls, |
1396 | &gc->truth_uuid, | 1402 | &gc->truth_uuid, |
1397 | &gc->challenge_response, | 1403 | &gc->challenge_response, |
1404 | &code, | ||
1398 | &satisfied); | 1405 | &satisfied); |
1399 | switch (cs) | 1406 | switch (cs) |
1400 | { | 1407 | { |
@@ -1415,15 +1422,14 @@ AH_handler_truth_get ( | |||
1415 | TALER_EC_GENERIC_DB_FETCH_FAILED, | 1422 | TALER_EC_GENERIC_DB_FETCH_FAILED, |
1416 | "verify_challenge_code"); | 1423 | "verify_challenge_code"); |
1417 | case ANASTASIS_DB_CODE_STATUS_NO_RESULTS: | 1424 | case ANASTASIS_DB_CODE_STATUS_NO_RESULTS: |
1418 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 1425 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
1419 | "No challenge known (challenge is invalidated after %u requests)\n", | 1426 | "Response code unknown (possibly expired). Testing if we may provide a new one.\n"); |
1420 | INITIAL_RETRY_COUNTER); | 1427 | gc->have_response = false; |
1421 | GNUNET_free (decrypted_truth); | 1428 | break; |
1422 | return TALER_MHD_reply_with_error (connection, | ||
1423 | MHD_HTTP_TOO_MANY_REQUESTS, | ||
1424 | TALER_EC_ANASTASIS_TRUTH_RATE_LIMITED, | ||
1425 | NULL); | ||
1426 | case ANASTASIS_DB_CODE_STATUS_VALID_CODE_STORED: | 1429 | case ANASTASIS_DB_CODE_STATUS_VALID_CODE_STORED: |
1430 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1431 | "Response code valid (%s)\n", | ||
1432 | satisfied ? "satisfied" : "unsatisfied"); | ||
1427 | if (satisfied) | 1433 | if (satisfied) |
1428 | { | 1434 | { |
1429 | GNUNET_free (decrypted_truth); | 1435 | GNUNET_free (decrypted_truth); |
@@ -1431,43 +1437,19 @@ AH_handler_truth_get ( | |||
1431 | connection); | 1437 | connection); |
1432 | } | 1438 | } |
1433 | /* continue with authorization plugin below */ | 1439 | /* continue with authorization plugin below */ |
1434 | { | 1440 | gc->code = code; |
1435 | enum GNUNET_DB_QueryStatus qs; | ||
1436 | |||
1437 | qs = db->get_unlimited_challenge_code ( | ||
1438 | db->cls, | ||
1439 | &gc->truth_uuid, | ||
1440 | gc->authorization->code_rotation_period, | ||
1441 | gc->authorization->code_validity_period, | ||
1442 | &gc->code); | ||
1443 | switch (qs) | ||
1444 | { | ||
1445 | case GNUNET_DB_STATUS_HARD_ERROR: | ||
1446 | case GNUNET_DB_STATUS_SOFT_ERROR: | ||
1447 | case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: | ||
1448 | GNUNET_break (0); | ||
1449 | GNUNET_free (decrypted_truth); | ||
1450 | return TALER_MHD_reply_with_error (gc->connection, | ||
1451 | MHD_HTTP_INTERNAL_SERVER_ERROR, | ||
1452 | TALER_EC_GENERIC_DB_FETCH_FAILED, | ||
1453 | "create_challenge_code"); | ||
1454 | case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: | ||
1455 | /* challenge code was stored successfully*/ | ||
1456 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1457 | "Got challenge code\n"); | ||
1458 | break; | ||
1459 | } | ||
1460 | } | ||
1461 | break; | 1441 | break; |
1462 | default: | 1442 | default: |
1463 | GNUNET_break (0); | 1443 | GNUNET_break (0); |
1464 | return MHD_NO; | 1444 | return MHD_NO; |
1465 | } | 1445 | } |
1466 | } | 1446 | } |
1467 | else | 1447 | if (! gc->have_response) |
1468 | { | 1448 | { |
1469 | /* Not security question and no answer: use plugin to check if | 1449 | /* Not security question and no answer: use plugin to check if |
1470 | decrypted truth is a valid challenge! */ | 1450 | decrypted truth is a valid challenge! */ |
1451 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1452 | "No challenge provided, creating fresh challenge\n"); | ||
1471 | { | 1453 | { |
1472 | enum GNUNET_GenericReturnValue ret; | 1454 | enum GNUNET_GenericReturnValue ret; |
1473 | 1455 | ||
@@ -1502,7 +1484,7 @@ AH_handler_truth_get ( | |||
1502 | &gc->truth_uuid, | 1484 | &gc->truth_uuid, |
1503 | gc->authorization->code_rotation_period, | 1485 | gc->authorization->code_rotation_period, |
1504 | gc->authorization->code_validity_period, | 1486 | gc->authorization->code_validity_period, |
1505 | INITIAL_RETRY_COUNTER, | 1487 | gc->authorization->retry_counter, |
1506 | &transmission_date, | 1488 | &transmission_date, |
1507 | &gc->code); | 1489 | &gc->code); |
1508 | switch (qs) | 1490 | switch (qs) |
diff --git a/src/include/anastasis_authorization_plugin.h b/src/include/anastasis_authorization_plugin.h index 55f6369..91a88f8 100644 --- a/src/include/anastasis_authorization_plugin.h +++ b/src/include/anastasis_authorization_plugin.h | |||
@@ -127,6 +127,12 @@ struct ANASTASIS_AuthorizationPlugin | |||
127 | bool payment_plugin_managed; | 127 | bool payment_plugin_managed; |
128 | 128 | ||
129 | /** | 129 | /** |
130 | * How often are retries allowed for challenges created | ||
131 | * by this plugin? | ||
132 | */ | ||
133 | uint32_t retry_counter; | ||
134 | |||
135 | /** | ||
130 | * How long should a generated challenge be valid for this type of method. | 136 | * How long should a generated challenge be valid for this type of method. |
131 | */ | 137 | */ |
132 | struct GNUNET_TIME_Relative code_validity_period; | 138 | struct GNUNET_TIME_Relative code_validity_period; |
diff --git a/src/include/anastasis_database_plugin.h b/src/include/anastasis_database_plugin.h index 079201d..565ad69 100644 --- a/src/include/anastasis_database_plugin.h +++ b/src/include/anastasis_database_plugin.h | |||
@@ -586,6 +586,7 @@ struct ANASTASIS_DatabasePlugin | |||
586 | * @param cls closure | 586 | * @param cls closure |
587 | * @param truth_uuid identification of the challenge which the code corresponds to | 587 | * @param truth_uuid identification of the challenge which the code corresponds to |
588 | * @param hashed_code code which the user provided and wants to verify | 588 | * @param hashed_code code which the user provided and wants to verify |
589 | * @param[out] code set to the original numeric code | ||
589 | * @param[out] satisfied set to true if the challenge is set to satisfied | 590 | * @param[out] satisfied set to true if the challenge is set to satisfied |
590 | * @return transaction status | 591 | * @return transaction status |
591 | */ | 592 | */ |
@@ -594,6 +595,7 @@ struct ANASTASIS_DatabasePlugin | |||
594 | void *cls, | 595 | void *cls, |
595 | const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid, | 596 | const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid, |
596 | const struct GNUNET_HashCode *hashed_code, | 597 | const struct GNUNET_HashCode *hashed_code, |
598 | uint64_t *code, | ||
597 | bool *satisfied); | 599 | bool *satisfied); |
598 | 600 | ||
599 | 601 | ||
@@ -655,38 +657,12 @@ struct ANASTASIS_DatabasePlugin | |||
655 | const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid, | 657 | const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid, |
656 | struct GNUNET_TIME_Relative rotation_period, | 658 | struct GNUNET_TIME_Relative rotation_period, |
657 | struct GNUNET_TIME_Relative validity_period, | 659 | struct GNUNET_TIME_Relative validity_period, |
658 | unsigned int retry_counter, | 660 | uint32_t retry_counter, |
659 | struct GNUNET_TIME_Absolute *retransmission_date, | 661 | struct GNUNET_TIME_Absolute *retransmission_date, |
660 | uint64_t *code); | 662 | uint64_t *code); |
661 | 663 | ||
662 | 664 | ||
663 | /** | 665 | /** |
664 | * Setup challenge code for a given challenge identified by the | ||
665 | * challenge public key. The function will first check if there is | ||
666 | * already a valid code for this challenge present and won't insert | ||
667 | * a new one in this case. This variant is not rate-limited, will | ||
668 | * return the existing challenge if it has not yet expired and will | ||
669 | * simply create new challenges when the old ones need to be | ||
670 | * rotated. | ||
671 | * | ||
672 | * @param cls closure | ||
673 | * @param truth_uuid the identifier for the challenge | ||
674 | * @param rotation_period for how long is the code available | ||
675 | * @param validity_period for how long is the code available | ||
676 | * @param[out] code set to the code which will be checked for later | ||
677 | * @return transaction status, | ||
678 | * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if @a code is now in the DB | ||
679 | */ | ||
680 | enum GNUNET_DB_QueryStatus | ||
681 | (*get_unlimited_challenge_code)( | ||
682 | void *cls, | ||
683 | const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid, | ||
684 | struct GNUNET_TIME_Relative rotation_period, | ||
685 | struct GNUNET_TIME_Relative validity_period, | ||
686 | uint64_t *code); | ||
687 | |||
688 | |||
689 | /** | ||
690 | * Remember in the database that we successfully sent a challenge. | 666 | * Remember in the database that we successfully sent a challenge. |
691 | * | 667 | * |
692 | * @param cls closure | 668 | * @param cls closure |
diff --git a/src/reducer/anastasis_api_recovery_redux.c b/src/reducer/anastasis_api_recovery_redux.c index 864ded2..fa550c6 100644 --- a/src/reducer/anastasis_api_recovery_redux.c +++ b/src/reducer/anastasis_api_recovery_redux.c | |||
@@ -722,7 +722,6 @@ answer_feedback_cb ( | |||
722 | uuid, | 722 | uuid, |
723 | err)); | 723 | err)); |
724 | } | 724 | } |
725 | GNUNET_break_op (0); | ||
726 | set_state (sctx->state, | 725 | set_state (sctx->state, |
727 | ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING); | 726 | ANASTASIS_RECOVERY_STATE_CHALLENGE_SELECTING); |
728 | sctx->cb (sctx->cb_cls, | 727 | sctx->cb (sctx->cb_cls, |
diff --git a/src/restclient/anastasis_api_keyshare_lookup.c b/src/restclient/anastasis_api_keyshare_lookup.c index c0c2812..5eeeee6 100644 --- a/src/restclient/anastasis_api_keyshare_lookup.c +++ b/src/restclient/anastasis_api_keyshare_lookup.c | |||
@@ -473,6 +473,8 @@ ANASTASIS_keyshare_lookup ( | |||
473 | { | 473 | { |
474 | answer_s = GNUNET_STRINGS_data_to_string_alloc (hashed_answer, | 474 | answer_s = GNUNET_STRINGS_data_to_string_alloc (hashed_answer, |
475 | sizeof (*hashed_answer)); | 475 | sizeof (*hashed_answer)); |
476 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
477 | "Querying challenge with existing response code\n"); | ||
476 | kslo->url = TALER_url_join (backend_url, | 478 | kslo->url = TALER_url_join (backend_url, |
477 | path, | 479 | path, |
478 | "response", | 480 | "response", |
@@ -486,6 +488,8 @@ ANASTASIS_keyshare_lookup ( | |||
486 | } | 488 | } |
487 | else | 489 | else |
488 | { | 490 | { |
491 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
492 | "Querying challenge without response code\n"); | ||
489 | kslo->url = TALER_url_join (backend_url, | 493 | kslo->url = TALER_url_join (backend_url, |
490 | path, | 494 | path, |
491 | "timeout_ms", | 495 | "timeout_ms", |
diff --git a/src/stasis/plugin_anastasis_postgres.c b/src/stasis/plugin_anastasis_postgres.c index 506c304..8ee16ad 100644 --- a/src/stasis/plugin_anastasis_postgres.c +++ b/src/stasis/plugin_anastasis_postgres.c | |||
@@ -1763,6 +1763,11 @@ struct CheckValidityContext | |||
1763 | struct PostgresClosure *pg; | 1763 | struct PostgresClosure *pg; |
1764 | 1764 | ||
1765 | /** | 1765 | /** |
1766 | * Set to the matching challenge code (if @e valid). | ||
1767 | */ | ||
1768 | uint64_t code; | ||
1769 | |||
1770 | /** | ||
1766 | * Set to true if a code matching @e hashed_code was found. | 1771 | * Set to true if a code matching @e hashed_code was found. |
1767 | */ | 1772 | */ |
1768 | bool valid; | 1773 | bool valid; |
@@ -1828,6 +1833,7 @@ check_valid_code (void *cls, | |||
1828 | cvc->hashed_code)) | 1833 | cvc->hashed_code)) |
1829 | { | 1834 | { |
1830 | cvc->valid = true; | 1835 | cvc->valid = true; |
1836 | cvc->code = server_code; | ||
1831 | cvc->satisfied = (0 != sat); | 1837 | cvc->satisfied = (0 != sat); |
1832 | } | 1838 | } |
1833 | else | 1839 | else |
@@ -1862,6 +1868,7 @@ check_valid_code (void *cls, | |||
1862 | * @param cls closure | 1868 | * @param cls closure |
1863 | * @param truth_uuid identification of the challenge which the code corresponds to | 1869 | * @param truth_uuid identification of the challenge which the code corresponds to |
1864 | * @param hashed_code code which the user provided and wants to verify | 1870 | * @param hashed_code code which the user provided and wants to verify |
1871 | * @param[out] code set to the original numeric code | ||
1865 | * @param[out] satisfied set to true if the challenge is set to satisfied | 1872 | * @param[out] satisfied set to true if the challenge is set to satisfied |
1866 | * @return code validity status | 1873 | * @return code validity status |
1867 | */ | 1874 | */ |
@@ -1870,6 +1877,7 @@ postgres_verify_challenge_code ( | |||
1870 | void *cls, | 1877 | void *cls, |
1871 | const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid, | 1878 | const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid, |
1872 | const struct GNUNET_HashCode *hashed_code, | 1879 | const struct GNUNET_HashCode *hashed_code, |
1880 | uint64_t *code, | ||
1873 | bool *satisfied) | 1881 | bool *satisfied) |
1874 | { | 1882 | { |
1875 | struct PostgresClosure *pg = cls; | 1883 | struct PostgresClosure *pg = cls; |
@@ -1897,6 +1905,7 @@ postgres_verify_challenge_code ( | |||
1897 | if ( (qs < 0) || | 1905 | if ( (qs < 0) || |
1898 | (cvc.db_failure) ) | 1906 | (cvc.db_failure) ) |
1899 | return ANASTASIS_DB_CODE_STATUS_HARD_ERROR; | 1907 | return ANASTASIS_DB_CODE_STATUS_HARD_ERROR; |
1908 | *code = cvc.code; | ||
1900 | if (cvc.valid) | 1909 | if (cvc.valid) |
1901 | { | 1910 | { |
1902 | *satisfied = cvc.satisfied; | 1911 | *satisfied = cvc.satisfied; |
@@ -2059,7 +2068,7 @@ postgres_create_challenge_code ( | |||
2059 | const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid, | 2068 | const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid, |
2060 | struct GNUNET_TIME_Relative rotation_period, | 2069 | struct GNUNET_TIME_Relative rotation_period, |
2061 | struct GNUNET_TIME_Relative validity_period, | 2070 | struct GNUNET_TIME_Relative validity_period, |
2062 | unsigned int retry_counter, | 2071 | uint32_t retry_counter, |
2063 | struct GNUNET_TIME_Absolute *retransmission_date, | 2072 | struct GNUNET_TIME_Absolute *retransmission_date, |
2064 | uint64_t *code) | 2073 | uint64_t *code) |
2065 | { | 2074 | { |
@@ -2117,15 +2126,22 @@ postgres_create_challenge_code ( | |||
2117 | case GNUNET_DB_STATUS_SOFT_ERROR: | 2126 | case GNUNET_DB_STATUS_SOFT_ERROR: |
2118 | goto retry; | 2127 | goto retry; |
2119 | case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: | 2128 | case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: |
2120 | /* no active challenge, create fresh one (below) */ | 2129 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
2130 | "No active challenge found, creating a fresh one\n"); | ||
2121 | break; | 2131 | break; |
2122 | case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: | 2132 | case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: |
2123 | if (0 == old_retry_counter) | 2133 | if (0 == old_retry_counter) |
2124 | { | 2134 | { |
2125 | rollback (pg); | 2135 | rollback (pg); |
2136 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
2137 | "Active challenge %llu has zero tries left, refusing to create another one\n", | ||
2138 | (unsigned long long) code); | ||
2126 | return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; | 2139 | return GNUNET_DB_STATUS_SUCCESS_NO_RESULTS; |
2127 | } | 2140 | } |
2128 | rollback (pg); | 2141 | rollback (pg); |
2142 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
2143 | "Active challenge has %u tries left, returning old challenge\n", | ||
2144 | (unsigned int) old_retry_counter); | ||
2129 | return qs; | 2145 | return qs; |
2130 | } | 2146 | } |
2131 | } | 2147 | } |
@@ -2158,132 +2174,9 @@ postgres_create_challenge_code ( | |||
2158 | rollback (pg); | 2174 | rollback (pg); |
2159 | return GNUNET_DB_STATUS_HARD_ERROR; | 2175 | return GNUNET_DB_STATUS_HARD_ERROR; |
2160 | case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: | 2176 | case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: |
2161 | break; | 2177 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
2162 | } | 2178 | "Created fresh challenge with %u tries left\n", |
2163 | } | 2179 | (unsigned int) retry_counter); |
2164 | qs = commit_transaction (pg); | ||
2165 | if (GNUNET_DB_STATUS_SOFT_ERROR == qs) | ||
2166 | goto retry; | ||
2167 | if (qs < 0) | ||
2168 | return qs; | ||
2169 | return GNUNET_DB_STATUS_SUCCESS_ONE_RESULT; | ||
2170 | retry: | ||
2171 | rollback (pg); | ||
2172 | } | ||
2173 | return GNUNET_DB_STATUS_SOFT_ERROR; | ||
2174 | } | ||
2175 | |||
2176 | |||
2177 | /** | ||
2178 | * Setup challenge code for a given challenge identified by the | ||
2179 | * challenge public key. The function will first check if there is | ||
2180 | * already a valid code for this challenge present and won't insert | ||
2181 | * a new one in this case. This variant is not rate-limited, will | ||
2182 | * return the existing challenge if it has not yet expired and will | ||
2183 | * simply create new challenges when the old ones need to be | ||
2184 | * rotated. | ||
2185 | * | ||
2186 | * @param cls closure | ||
2187 | * @param truth_uuid the identifier for the challenge | ||
2188 | * @param rotation_period for how long is the code available | ||
2189 | * @param validity_period for how long is the code available | ||
2190 | * @param[out] code set to the code which will be checked for later | ||
2191 | * @return transaction status, | ||
2192 | * #GNUNET_DB_STATUS_SUCCESS_ONE_RESULT if @a code is now in the DB | ||
2193 | */ | ||
2194 | static enum GNUNET_DB_QueryStatus | ||
2195 | postgres_get_unlimited_challenge_code ( | ||
2196 | void *cls, | ||
2197 | const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid, | ||
2198 | struct GNUNET_TIME_Relative rotation_period, | ||
2199 | struct GNUNET_TIME_Relative validity_period, | ||
2200 | uint64_t *code) | ||
2201 | { | ||
2202 | struct PostgresClosure *pg = cls; | ||
2203 | enum GNUNET_DB_QueryStatus qs; | ||
2204 | struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); | ||
2205 | struct GNUNET_TIME_Absolute expiration_date; | ||
2206 | struct GNUNET_TIME_Absolute ex_rot; | ||
2207 | |||
2208 | check_connection (pg); | ||
2209 | GNUNET_TIME_round_abs (&now); | ||
2210 | expiration_date = GNUNET_TIME_absolute_add (now, | ||
2211 | validity_period); | ||
2212 | ex_rot = GNUNET_TIME_absolute_subtract (now, | ||
2213 | rotation_period); | ||
2214 | for (unsigned int retries = 0; retries<MAX_RETRIES; retries++) | ||
2215 | { | ||
2216 | if (GNUNET_OK != | ||
2217 | begin_transaction (pg, | ||
2218 | "get_unlimited_challenge_code")) | ||
2219 | { | ||
2220 | GNUNET_break (0); | ||
2221 | return GNUNET_DB_STATUS_HARD_ERROR; | ||
2222 | } | ||
2223 | |||
2224 | { | ||
2225 | struct GNUNET_PQ_QueryParam params[] = { | ||
2226 | GNUNET_PQ_query_param_auto_from_type (truth_uuid), | ||
2227 | TALER_PQ_query_param_absolute_time (&now), | ||
2228 | TALER_PQ_query_param_absolute_time (&ex_rot), | ||
2229 | GNUNET_PQ_query_param_end | ||
2230 | }; | ||
2231 | struct GNUNET_PQ_ResultSpec rs[] = { | ||
2232 | GNUNET_PQ_result_spec_uint64 ("code", | ||
2233 | code), | ||
2234 | GNUNET_PQ_result_spec_end | ||
2235 | }; | ||
2236 | enum GNUNET_DB_QueryStatus qs; | ||
2237 | |||
2238 | qs = GNUNET_PQ_eval_prepared_singleton_select (pg->conn, | ||
2239 | "challengecode_select_meta", | ||
2240 | params, | ||
2241 | rs); | ||
2242 | switch (qs) | ||
2243 | { | ||
2244 | case GNUNET_DB_STATUS_HARD_ERROR: | ||
2245 | GNUNET_break (0); | ||
2246 | rollback (pg); | ||
2247 | return qs; | ||
2248 | case GNUNET_DB_STATUS_SOFT_ERROR: | ||
2249 | goto retry; | ||
2250 | case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: | ||
2251 | /* no active challenge, create fresh one (below) */ | ||
2252 | break; | ||
2253 | case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: | ||
2254 | rollback (pg); | ||
2255 | return qs; | ||
2256 | } | ||
2257 | } | ||
2258 | |||
2259 | *code = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_NONCE, | ||
2260 | NONCE_MAX_VALUE); | ||
2261 | { | ||
2262 | uint32_t retry_counter = UINT32_MAX; | ||
2263 | struct GNUNET_PQ_QueryParam params[] = { | ||
2264 | GNUNET_PQ_query_param_auto_from_type (truth_uuid), | ||
2265 | GNUNET_PQ_query_param_uint64 (code), | ||
2266 | TALER_PQ_query_param_absolute_time (&now), | ||
2267 | TALER_PQ_query_param_absolute_time (&expiration_date), | ||
2268 | GNUNET_PQ_query_param_uint32 (&retry_counter), | ||
2269 | GNUNET_PQ_query_param_end | ||
2270 | }; | ||
2271 | |||
2272 | qs = GNUNET_PQ_eval_prepared_non_select (pg->conn, | ||
2273 | "challengecode_insert", | ||
2274 | params); | ||
2275 | switch (qs) | ||
2276 | { | ||
2277 | case GNUNET_DB_STATUS_HARD_ERROR: | ||
2278 | rollback (pg); | ||
2279 | return GNUNET_DB_STATUS_HARD_ERROR; | ||
2280 | case GNUNET_DB_STATUS_SOFT_ERROR: | ||
2281 | goto retry; | ||
2282 | case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS: | ||
2283 | GNUNET_break (0); | ||
2284 | rollback (pg); | ||
2285 | return GNUNET_DB_STATUS_HARD_ERROR; | ||
2286 | case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT: | ||
2287 | break; | 2180 | break; |
2288 | } | 2181 | } |
2289 | } | 2182 | } |
@@ -2675,7 +2568,7 @@ libanastasis_plugin_db_postgres_init (void *cls) | |||
2675 | " FROM anastasis_challengecode" | 2568 | " FROM anastasis_challengecode" |
2676 | " WHERE truth_uuid=$1" | 2569 | " WHERE truth_uuid=$1" |
2677 | " AND expiration_date > $2" | 2570 | " AND expiration_date > $2" |
2678 | " AND retry_counter > 0;", | 2571 | " AND retry_counter != 0;", |
2679 | 2), | 2572 | 2), |
2680 | GNUNET_PQ_make_prepare ("challengecode_set_satisfied", | 2573 | GNUNET_PQ_make_prepare ("challengecode_set_satisfied", |
2681 | "UPDATE anastasis_challengecode" | 2574 | "UPDATE anastasis_challengecode" |
@@ -2715,7 +2608,7 @@ libanastasis_plugin_db_postgres_init (void *cls) | |||
2715 | " SET retry_counter=retry_counter - 1" | 2608 | " SET retry_counter=retry_counter - 1" |
2716 | " WHERE truth_uuid=$1" | 2609 | " WHERE truth_uuid=$1" |
2717 | " AND code=$2" | 2610 | " AND code=$2" |
2718 | " AND retry_counter > 0;", | 2611 | " AND retry_counter != 0;", |
2719 | 1), | 2612 | 1), |
2720 | GNUNET_PQ_make_prepare ("challengepayment_dec_counter", | 2613 | GNUNET_PQ_make_prepare ("challengepayment_dec_counter", |
2721 | "UPDATE anastasis_challenge_payment" | 2614 | "UPDATE anastasis_challenge_payment" |
@@ -2807,7 +2700,6 @@ libanastasis_plugin_db_postgres_init (void *cls) | |||
2807 | plugin->test_challenge_code_satisfied = | 2700 | plugin->test_challenge_code_satisfied = |
2808 | &postgres_test_challenge_code_satisfied; | 2701 | &postgres_test_challenge_code_satisfied; |
2809 | plugin->create_challenge_code = &postgres_create_challenge_code; | 2702 | plugin->create_challenge_code = &postgres_create_challenge_code; |
2810 | plugin->get_unlimited_challenge_code = &postgres_get_unlimited_challenge_code; | ||
2811 | plugin->mark_challenge_sent = &postgres_mark_challenge_sent; | 2703 | plugin->mark_challenge_sent = &postgres_mark_challenge_sent; |
2812 | plugin->challenge_gc = &postgres_challenge_gc; | 2704 | plugin->challenge_gc = &postgres_challenge_gc; |
2813 | plugin->record_truth_upload_payment = &postgres_record_truth_upload_payment; | 2705 | plugin->record_truth_upload_payment = &postgres_record_truth_upload_payment; |
diff --git a/src/stasis/test_anastasis_db.c b/src/stasis/test_anastasis_db.c index 8f11827..204307a 100644 --- a/src/stasis/test_anastasis_db.c +++ b/src/stasis/test_anastasis_db.c | |||
@@ -270,11 +270,13 @@ run (void *cls) | |||
270 | &c_hash); | 270 | &c_hash); |
271 | { | 271 | { |
272 | bool sat; | 272 | bool sat; |
273 | uint64_t r_code; | ||
273 | 274 | ||
274 | FAILIF (ANASTASIS_DB_CODE_STATUS_CHALLENGE_CODE_MISMATCH != | 275 | FAILIF (ANASTASIS_DB_CODE_STATUS_CHALLENGE_CODE_MISMATCH != |
275 | plugin->verify_challenge_code (plugin->cls, | 276 | plugin->verify_challenge_code (plugin->cls, |
276 | &truth_uuid, | 277 | &truth_uuid, |
277 | &c_hash, | 278 | &c_hash, |
279 | &r_code, | ||
278 | &sat)); | 280 | &sat)); |
279 | 281 | ||
280 | ANASTASIS_hash_answer (challenge_code, | 282 | ANASTASIS_hash_answer (challenge_code, |
@@ -283,6 +285,7 @@ run (void *cls) | |||
283 | plugin->verify_challenge_code (plugin->cls, | 285 | plugin->verify_challenge_code (plugin->cls, |
284 | &truth_uuid, | 286 | &truth_uuid, |
285 | &c_hash, | 287 | &c_hash, |
288 | &r_code, | ||
286 | &sat)); | 289 | &sat)); |
287 | } | 290 | } |
288 | if (-1 == result) | 291 | if (-1 == result) |