aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2021-08-27 17:44:01 +0200
committerChristian Grothoff <christian@grothoff.org>2021-08-27 17:44:01 +0200
commit2e2a558a59d0e7a25953cddf2afb67b7ab96135c (patch)
treea8bbc38cdb83092cea3624a855d63a5fb8a71603
parent3a6466bb3854863b4b35deb08cb2e4ed03ebf12b (diff)
downloadanastasis-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.c5
-rw-r--r--src/authorization/anastasis_authorization_plugin_file.c6
-rw-r--r--src/authorization/anastasis_authorization_plugin_iban.c1
-rw-r--r--src/authorization/anastasis_authorization_plugin_post.c7
-rw-r--r--src/authorization/anastasis_authorization_plugin_sms.c5
-rw-r--r--src/backend/anastasis-httpd_truth.c56
-rw-r--r--src/include/anastasis_authorization_plugin.h6
-rw-r--r--src/include/anastasis_database_plugin.h30
-rw-r--r--src/reducer/anastasis_api_recovery_redux.c1
-rw-r--r--src/restclient/anastasis_api_keyshare_lookup.c4
-rw-r--r--src/stasis/plugin_anastasis_postgres.c154
-rw-r--r--src/stasis/test_anastasis_db.c3
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 */
33struct PostContext 39struct 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
59struct GetContext 60struct 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;
2170retry:
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 */
2194static enum GNUNET_DB_QueryStatus
2195postgres_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)