anastasis

Credential backup and recovery protocol and service
Log | Files | Refs | Submodules | README | LICENSE

anastasis-httpd_truth-solve.c (46552B)


      1 /*
      2   This file is part of Anastasis
      3   Copyright (C) 2019-2022 Anastasis SARL
      4 
      5   Anastasis is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   Anastasis; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file anastasis-httpd_truth-solve.c
     18  * @brief functions to handle incoming requests on /truth/$TID/solve
     19  * @author Dennis Neufeld
     20  * @author Dominik Meister
     21  * @author Christian Grothoff
     22  */
     23 #include "platform.h"
     24 struct SolveContext;
     25 #define TALER_MERCHANT_POST_PRIVATE_ORDERS_RESULT_CLOSURE struct SolveContext
     26 #define TALER_MERCHANT_GET_PRIVATE_ORDER_RESULT_CLOSURE struct SolveContext
     27 #include "anastasis-httpd.h"
     28 #include "anastasis_service.h"
     29 #include "anastasis-httpd_truth.h"
     30 #include <gnunet/gnunet_util_lib.h>
     31 #include <gnunet/gnunet_rest_lib.h>
     32 #include "anastasis_authorization_lib.h"
     33 #include <taler/taler_merchant_service.h>
     34 #include <taler/taler_json_lib.h>
     35 #include <taler/taler_mhd_lib.h>
     36 #include <taler/merchant/post-private-orders.h>
     37 #include <taler/merchant/get-private-orders-ORDER_ID.h>
     38 
     39 /**
     40  * What is the maximum frequency at which we allow
     41  * clients to attempt to answer security questions?
     42  */
     43 #define MAX_QUESTION_FREQ GNUNET_TIME_relative_multiply ( \
     44           GNUNET_TIME_UNIT_SECONDS, 30)
     45 
     46 /**
     47  * How long should the wallet check for auto-refunds before giving up?
     48  */
     49 #define AUTO_REFUND_TIMEOUT GNUNET_TIME_relative_multiply ( \
     50           GNUNET_TIME_UNIT_MINUTES, 2)
     51 
     52 
     53 /**
     54  * How many retries do we allow per code?
     55  */
     56 #define INITIAL_RETRY_COUNTER 3
     57 
     58 
     59 struct SolveContext
     60 {
     61 
     62   /**
     63    * Payment Identifier
     64    */
     65   struct ANASTASIS_PaymentSecretP payment_identifier;
     66 
     67   /**
     68    * Public key of the challenge which is solved.
     69    */
     70   struct ANASTASIS_CRYPTO_TruthUUIDP truth_uuid;
     71 
     72   /**
     73    * Key to decrypt the truth.
     74    */
     75   struct ANASTASIS_CRYPTO_TruthKeyP truth_key;
     76 
     77   /**
     78    * Cost for paying the challenge.
     79    */
     80   struct TALER_Amount challenge_cost;
     81 
     82   /**
     83    * Our handler context.
     84    */
     85   struct TM_HandlerContext *hc;
     86 
     87   /**
     88    * Opaque parsing context.
     89    */
     90   void *opaque_post_parsing_context;
     91 
     92   /**
     93    * Uploaded JSON data, NULL if upload is not yet complete.
     94    */
     95   json_t *root;
     96 
     97   /**
     98    * Kept in DLL for shutdown handling while suspended.
     99    */
    100   struct SolveContext *next;
    101 
    102   /**
    103    * Kept in DLL for shutdown handling while suspended.
    104    */
    105   struct SolveContext *prev;
    106 
    107   /**
    108    * Connection handle for closing or resuming
    109    */
    110   struct MHD_Connection *connection;
    111 
    112   /**
    113    * Reference to the authorization plugin which was loaded
    114    */
    115   struct ANASTASIS_AuthorizationPlugin *authorization;
    116 
    117   /**
    118    * Status of the authorization
    119    */
    120   struct ANASTASIS_AUTHORIZATION_State *as;
    121 
    122   /**
    123    * Used while we are awaiting proposal creation.
    124    */
    125   struct TALER_MERCHANT_PostPrivateOrdersHandle *po;
    126 
    127   /**
    128    * Used while we are waiting payment.
    129    */
    130   struct TALER_MERCHANT_GetPrivateOrderHandle *cpo;
    131 
    132   /**
    133    * HTTP response code to use on resume, if non-NULL.
    134    */
    135   struct MHD_Response *resp;
    136 
    137   /**
    138    * Our entry in the #to_heap, or NULL.
    139    */
    140   struct GNUNET_CONTAINER_HeapNode *hn;
    141 
    142   /**
    143    * Challenge response we got from the request.
    144    */
    145   struct GNUNET_HashCode challenge_response;
    146 
    147   /**
    148    * How long do we wait at most for payment or
    149    * authorization?
    150    */
    151   struct GNUNET_TIME_Absolute timeout;
    152 
    153   /**
    154    * Random authorization code we are using.
    155    */
    156   uint64_t code;
    157 
    158   /**
    159    * HTTP response code to use on resume, if resp is set.
    160    */
    161   unsigned int response_code;
    162 
    163   /**
    164    * true if client did not provide a payment secret / order ID.
    165    */
    166   bool no_payment_identifier_provided;
    167 
    168   /**
    169    * True if this entry is in the #gc_head DLL.
    170    */
    171   bool in_list;
    172 
    173   /**
    174    * True if this entry is currently suspended.
    175    */
    176   bool suspended;
    177 
    178 };
    179 
    180 
    181 /**
    182  * Head of linked list over all authorization processes
    183  */
    184 static struct SolveContext *gc_head;
    185 
    186 /**
    187  * Tail of linked list over all authorization processes
    188  */
    189 static struct SolveContext *gc_tail;
    190 
    191 /**
    192  * Task running #do_timeout().
    193  */
    194 static struct GNUNET_SCHEDULER_Task *to_task;
    195 
    196 
    197 /**
    198  * Generate a response telling the client that answering this
    199  * challenge failed because the rate limit has been exceeded.
    200  *
    201  * @param gc request to answer for
    202  * @return MHD status code
    203  */
    204 static enum MHD_Result
    205 reply_rate_limited (const struct SolveContext *gc)
    206 {
    207   if (NULL != gc->authorization)
    208     return TALER_MHD_REPLY_JSON_PACK (
    209       gc->connection,
    210       MHD_HTTP_TOO_MANY_REQUESTS,
    211       TALER_MHD_PACK_EC (TALER_EC_ANASTASIS_TRUTH_RATE_LIMITED),
    212       GNUNET_JSON_pack_uint64 ("request_limit",
    213                                gc->authorization->retry_counter),
    214       GNUNET_JSON_pack_time_rel ("request_frequency",
    215                                  gc->authorization->code_rotation_period));
    216   /* must be security question */
    217   return TALER_MHD_REPLY_JSON_PACK (
    218     gc->connection,
    219     MHD_HTTP_TOO_MANY_REQUESTS,
    220     TALER_MHD_PACK_EC (TALER_EC_ANASTASIS_TRUTH_RATE_LIMITED),
    221     GNUNET_JSON_pack_uint64 ("request_limit",
    222                              INITIAL_RETRY_COUNTER),
    223     GNUNET_JSON_pack_time_rel ("request_frequency",
    224                                MAX_QUESTION_FREQ));
    225 }
    226 
    227 
    228 /**
    229  * Timeout requests that are past their due date.
    230  *
    231  * @param cls NULL
    232  */
    233 static void
    234 do_timeout (void *cls)
    235 {
    236   struct SolveContext *gc;
    237 
    238   (void) cls;
    239   to_task = NULL;
    240   while (NULL !=
    241          (gc = GNUNET_CONTAINER_heap_peek (AH_to_heap)))
    242   {
    243     if (GNUNET_TIME_absolute_is_future (gc->timeout))
    244       break;
    245     if (gc->suspended)
    246     {
    247       /* Test needed as we may have a "concurrent"
    248          wakeup from another task that did not clear
    249          this entry from the heap before the
    250          response process concluded. */
    251       gc->suspended = false;
    252       MHD_resume_connection (gc->connection);
    253     }
    254     GNUNET_assert (NULL != gc->hn);
    255     gc->hn = NULL;
    256     GNUNET_assert (gc ==
    257                    GNUNET_CONTAINER_heap_remove_root (AH_to_heap));
    258   }
    259   if (NULL == gc)
    260     return;
    261   to_task = GNUNET_SCHEDULER_add_at (gc->timeout,
    262                                      &do_timeout,
    263                                      NULL);
    264 }
    265 
    266 
    267 void
    268 AH_truth_solve_shutdown (void)
    269 {
    270   struct SolveContext *gc;
    271 
    272   while (NULL != (gc = gc_head))
    273   {
    274     GNUNET_CONTAINER_DLL_remove (gc_head,
    275                                  gc_tail,
    276                                  gc);
    277     gc->in_list = false;
    278     if (NULL != gc->cpo)
    279     {
    280       TALER_MERCHANT_get_private_order_cancel (gc->cpo);
    281       gc->cpo = NULL;
    282     }
    283     if (NULL != gc->po)
    284     {
    285       TALER_MERCHANT_post_private_orders_cancel (gc->po);
    286       gc->po = NULL;
    287     }
    288     if (gc->suspended)
    289     {
    290       gc->suspended = false;
    291       MHD_resume_connection (gc->connection);
    292     }
    293     if (NULL != gc->as)
    294     {
    295       gc->authorization->cleanup (gc->as);
    296       gc->as = NULL;
    297       gc->authorization = NULL;
    298     }
    299   }
    300   ANASTASIS_authorization_plugin_shutdown ();
    301   if (NULL != to_task)
    302   {
    303     GNUNET_SCHEDULER_cancel (to_task);
    304     to_task = NULL;
    305   }
    306 }
    307 
    308 
    309 /**
    310  * Callback used to notify the application about completed requests.
    311  * Cleans up the requests data structures.
    312  *
    313  * @param[in,out] hc
    314  */
    315 static void
    316 request_done (struct TM_HandlerContext *hc)
    317 {
    318   struct SolveContext *gc = hc->ctx;
    319 
    320   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    321               "Request completed\n");
    322   if (NULL == gc)
    323     return;
    324   hc->cc = NULL;
    325   GNUNET_assert (! gc->suspended);
    326   if (gc->in_list)
    327   {
    328     GNUNET_CONTAINER_DLL_remove (gc_head,
    329                                  gc_tail,
    330                                  gc);
    331     gc->in_list = false;
    332   }
    333   if (NULL != gc->hn)
    334   {
    335     GNUNET_assert (gc ==
    336                    GNUNET_CONTAINER_heap_remove_node (gc->hn));
    337     gc->hn = NULL;
    338   }
    339   if (NULL != gc->as)
    340   {
    341     gc->authorization->cleanup (gc->as);
    342     gc->authorization = NULL;
    343     gc->as = NULL;
    344   }
    345   if (NULL != gc->cpo)
    346   {
    347     TALER_MERCHANT_get_private_order_cancel (gc->cpo);
    348     gc->cpo = NULL;
    349   }
    350   if (NULL != gc->po)
    351   {
    352     TALER_MERCHANT_post_private_orders_cancel (gc->po);
    353     gc->po = NULL;
    354   }
    355   if (NULL != gc->root)
    356   {
    357     json_decref (gc->root);
    358     gc->root = NULL;
    359   }
    360   TALER_MHD_parse_post_cleanup_callback (gc->opaque_post_parsing_context);
    361   GNUNET_free (gc);
    362   hc->ctx = NULL;
    363 }
    364 
    365 
    366 /**
    367  * Transmit a payment request for @a order_id on @a connection
    368  *
    369  * @param gc context to make payment request for
    370  */
    371 static void
    372 make_payment_request (struct SolveContext *gc)
    373 {
    374   struct MHD_Response *resp;
    375 
    376   resp = MHD_create_response_from_buffer (0,
    377                                           NULL,
    378                                           MHD_RESPMEM_PERSISTENT);
    379   GNUNET_assert (NULL != resp);
    380   TALER_MHD_add_global_headers (resp,
    381                                 false);
    382   {
    383     char *hdr;
    384     char *order_id;
    385     const char *pfx;
    386     const char *hn;
    387 
    388     if (0 == strncasecmp ("https://",
    389                           AH_backend_url,
    390                           strlen ("https://")))
    391     {
    392       pfx = "taler://";
    393       hn = &AH_backend_url[strlen ("https://")];
    394     }
    395     else if (0 == strncasecmp ("http://",
    396                                AH_backend_url,
    397                                strlen ("http://")))
    398     {
    399       pfx = "taler+http://";
    400       hn = &AH_backend_url[strlen ("http://")];
    401     }
    402     else
    403     {
    404       /* This invariant holds as per check in anastasis-httpd.c */
    405       GNUNET_assert (0);
    406     }
    407     /* This invariant holds as per check in anastasis-httpd.c */
    408     GNUNET_assert (0 != strlen (hn));
    409 
    410     order_id = GNUNET_STRINGS_data_to_string_alloc (
    411       &gc->payment_identifier,
    412       sizeof (gc->payment_identifier));
    413     GNUNET_asprintf (&hdr,
    414                      "%spay/%s%s/",
    415                      pfx,
    416                      hn,
    417                      order_id);
    418     GNUNET_free (order_id);
    419     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    420                 "Sending payment request `%s'\n",
    421                 hdr);
    422     GNUNET_break (MHD_YES ==
    423                   MHD_add_response_header (resp,
    424                                            ANASTASIS_HTTP_HEADER_TALER,
    425                                            hdr));
    426     GNUNET_free (hdr);
    427   }
    428   gc->resp = resp;
    429   gc->response_code = MHD_HTTP_PAYMENT_REQUIRED;
    430 }
    431 
    432 
    433 /**
    434  * Callbacks of this type are used to serve the result of submitting a
    435  * /contract request to a merchant.
    436  *
    437  * @param cls our `struct SolveContext`
    438  * @param por response details
    439  */
    440 static void
    441 proposal_cb (struct SolveContext *gc,
    442              const struct TALER_MERCHANT_PostPrivateOrdersResponse *por)
    443 {
    444   enum GNUNET_DB_QueryStatus qs;
    445 
    446   gc->po = NULL;
    447   GNUNET_assert (gc->in_list);
    448   GNUNET_CONTAINER_DLL_remove (gc_head,
    449                                gc_tail,
    450                                gc);
    451   gc->in_list = false;
    452   GNUNET_assert (gc->suspended);
    453   gc->suspended = false;
    454   MHD_resume_connection (gc->connection);
    455   AH_trigger_daemon (NULL);
    456   if (MHD_HTTP_OK != por->hr.http_status)
    457   {
    458     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    459                 "Backend returned status %u/%d\n",
    460                 por->hr.http_status,
    461                 (int) por->hr.ec);
    462     GNUNET_break (0);
    463     gc->resp = TALER_MHD_MAKE_JSON_PACK (
    464       GNUNET_JSON_pack_uint64 ("code",
    465                                TALER_EC_ANASTASIS_TRUTH_PAYMENT_CREATE_BACKEND_ERROR),
    466       GNUNET_JSON_pack_string ("hint",
    467                                "Failed to setup order with merchant backend"),
    468       GNUNET_JSON_pack_uint64 ("backend-ec",
    469                                por->hr.ec),
    470       GNUNET_JSON_pack_uint64 ("backend-http-status",
    471                                por->hr.http_status),
    472       GNUNET_JSON_pack_allow_null (
    473         GNUNET_JSON_pack_object_steal ("backend-reply",
    474                                        (json_t *) por->hr.reply)));
    475     gc->response_code = MHD_HTTP_BAD_GATEWAY;
    476     return;
    477   }
    478   qs = ANASTASIS_DB_record_challenge_payment (
    479     &gc->truth_uuid,
    480     &gc->payment_identifier,
    481     &gc->challenge_cost);
    482   if (0 >= qs)
    483   {
    484     GNUNET_break (0);
    485     gc->resp = TALER_MHD_make_error (TALER_EC_GENERIC_DB_STORE_FAILED,
    486                                      "record challenge payment");
    487     gc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
    488     return;
    489   }
    490   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    491               "Setup fresh order, creating payment request\n");
    492   make_payment_request (gc);
    493 }
    494 
    495 
    496 /**
    497  * Callback to process a GET /check-payment request
    498  *
    499  * @param cls our `struct SolveContext`
    500  * @param osr order status
    501  */
    502 static void
    503 check_payment_cb (struct SolveContext *gc,
    504                   const struct TALER_MERCHANT_GetPrivateOrderResponse *osr)
    505 
    506 {
    507   const struct TALER_MERCHANT_HttpResponse *hr = &osr->hr;
    508 
    509   gc->cpo = NULL;
    510   GNUNET_assert (gc->in_list);
    511   GNUNET_CONTAINER_DLL_remove (gc_head,
    512                                gc_tail,
    513                                gc);
    514   gc->in_list = false;
    515   GNUNET_assert (gc->suspended);
    516   gc->suspended = false;
    517   MHD_resume_connection (gc->connection);
    518   AH_trigger_daemon (NULL);
    519 
    520   switch (hr->http_status)
    521   {
    522   case MHD_HTTP_OK:
    523     GNUNET_assert (NULL != osr);
    524     break;
    525   case MHD_HTTP_NOT_FOUND:
    526     /* We created this order before, how can it be not found now? */
    527     GNUNET_break (0);
    528     gc->resp = TALER_MHD_make_error (TALER_EC_ANASTASIS_TRUTH_ORDER_DISAPPEARED,
    529                                      NULL);
    530     gc->response_code = MHD_HTTP_BAD_GATEWAY;
    531     return;
    532   case MHD_HTTP_BAD_GATEWAY:
    533     gc->resp = TALER_MHD_make_error (
    534       TALER_EC_ANASTASIS_TRUTH_BACKEND_EXCHANGE_BAD,
    535       NULL);
    536     gc->response_code = MHD_HTTP_BAD_GATEWAY;
    537     return;
    538   case MHD_HTTP_GATEWAY_TIMEOUT:
    539     gc->resp = TALER_MHD_make_error (TALER_EC_ANASTASIS_GENERIC_BACKEND_TIMEOUT,
    540                                      "Timeout check payment status");
    541     GNUNET_assert (NULL != gc->resp);
    542     gc->response_code = MHD_HTTP_GATEWAY_TIMEOUT;
    543     return;
    544   default:
    545     {
    546       char status[14];
    547 
    548       GNUNET_snprintf (status,
    549                        sizeof (status),
    550                        "%u",
    551                        hr->http_status);
    552       gc->resp = TALER_MHD_make_error (
    553         TALER_EC_ANASTASIS_TRUTH_UNEXPECTED_PAYMENT_STATUS,
    554         status);
    555       GNUNET_assert (NULL != gc->resp);
    556       gc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
    557       return;
    558     }
    559   }
    560 
    561   GNUNET_assert (MHD_HTTP_OK == hr->http_status);
    562   switch (osr->details.ok.status)
    563   {
    564   case TALER_MERCHANT_OSC_PAID:
    565     {
    566       enum GNUNET_DB_QueryStatus qs;
    567 
    568       qs = ANASTASIS_DB_update_challenge_payment (
    569         &gc->truth_uuid,
    570         &gc->payment_identifier);
    571       if (0 <= qs)
    572       {
    573         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    574                     "Order has been paid, continuing with request processing\n")
    575         ;
    576         return; /* continue as planned */
    577       }
    578       GNUNET_break (0);
    579       gc->resp = TALER_MHD_make_error (TALER_EC_GENERIC_DB_STORE_FAILED,
    580                                        "update challenge payment");
    581       gc->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
    582       return; /* continue as planned */
    583     }
    584   case TALER_MERCHANT_OSC_CLAIMED:
    585   case TALER_MERCHANT_OSC_UNPAID:
    586     /* repeat payment request */
    587     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    588                 "Order remains unpaid, sending payment request again\n");
    589     make_payment_request (gc);
    590     return;
    591   }
    592   /* should never get here */
    593   GNUNET_break (0);
    594 }
    595 
    596 
    597 /**
    598  * Helper function used to ask our backend to begin processing a
    599  * payment for the user's account.  May perform asynchronous
    600  * operations by suspending the connection if required.
    601  *
    602  * @param gc context to begin payment for.
    603  * @return MHD status code
    604  */
    605 static enum MHD_Result
    606 begin_payment (struct SolveContext *gc)
    607 {
    608   enum GNUNET_DB_QueryStatus qs;
    609   char *order_id;
    610 
    611   qs = ANASTASIS_DB_lookup_challenge_payment (
    612     &gc->truth_uuid,
    613     &gc->payment_identifier);
    614   if (qs < 0)
    615   {
    616     GNUNET_break (0);
    617     return TALER_MHD_reply_with_error (gc->connection,
    618                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    619                                        TALER_EC_GENERIC_DB_FETCH_FAILED,
    620                                        "lookup challenge payment");
    621   }
    622   GNUNET_assert (! gc->in_list);
    623   gc->in_list = true;
    624   GNUNET_CONTAINER_DLL_insert (gc_tail,
    625                                gc_head,
    626                                gc);
    627   GNUNET_assert (! gc->suspended);
    628   gc->suspended = true;
    629   MHD_suspend_connection (gc->connection);
    630   if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
    631   {
    632     /* We already created the order, check if it was paid */
    633     struct GNUNET_TIME_Relative timeout;
    634 
    635     order_id = GNUNET_STRINGS_data_to_string_alloc (
    636       &gc->payment_identifier,
    637       sizeof (gc->payment_identifier));
    638     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    639                 "Order exists, checking payment status for order `%s'\n",
    640                 order_id);
    641     timeout = GNUNET_TIME_absolute_get_remaining (gc->timeout);
    642     gc->cpo = TALER_MERCHANT_get_private_order_create (AH_ctx,
    643                                                        AH_backend_url,
    644                                                        order_id);
    645     GNUNET_assert (NULL != gc->cpo);
    646     GNUNET_assert (
    647       GNUNET_OK ==
    648       TALER_MERCHANT_get_private_order_set_options (
    649         gc->cpo,
    650         TALER_MERCHANT_get_private_order_option_timeout (timeout)));
    651     GNUNET_assert (TALER_EC_NONE ==
    652                    TALER_MERCHANT_get_private_order_start (gc->cpo,
    653                                                            &check_payment_cb,
    654                                                            gc));
    655   }
    656   else
    657   {
    658     /* Create a fresh order */
    659     struct GNUNET_TIME_Timestamp pay_deadline;
    660 
    661     GNUNET_CRYPTO_random_block (&gc->payment_identifier,
    662                                 sizeof (struct ANASTASIS_PaymentSecretP));
    663     order_id = GNUNET_STRINGS_data_to_string_alloc (
    664       &gc->payment_identifier,
    665       sizeof (gc->payment_identifier));
    666     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    667                 "Creating fresh order `%s'\n",
    668                 order_id);
    669     pay_deadline = GNUNET_TIME_relative_to_timestamp (
    670       ANASTASIS_CHALLENGE_OFFER_LIFETIME);
    671     {
    672       json_t *order;
    673 
    674       order = GNUNET_JSON_PACK (
    675         TALER_JSON_pack_amount ("amount",
    676                                 &gc->challenge_cost),
    677         GNUNET_JSON_pack_string ("summary",
    678                                  "challenge fee for anastasis service"),
    679         GNUNET_JSON_pack_string ("order_id",
    680                                  order_id),
    681         GNUNET_JSON_pack_time_rel ("auto_refund",
    682                                    AUTO_REFUND_TIMEOUT),
    683         GNUNET_JSON_pack_timestamp ("pay_deadline",
    684                                     pay_deadline));
    685       gc->po = TALER_MERCHANT_post_private_orders_create (AH_ctx,
    686                                                           AH_backend_url,
    687                                                           order);
    688       json_decref (order);
    689     }
    690     GNUNET_assert (
    691       GNUNET_OK ==
    692       TALER_MERCHANT_post_private_orders_set_options (
    693         gc->po,
    694         TALER_MERCHANT_post_private_orders_option_create_token (false),
    695         TALER_MERCHANT_post_private_orders_option_refund_delay (
    696           AUTO_REFUND_TIMEOUT)));
    697     GNUNET_assert (TALER_EC_NONE ==
    698                    TALER_MERCHANT_post_private_orders_start (gc->po,
    699                                                              &proposal_cb,
    700                                                              gc));
    701   }
    702   GNUNET_free (order_id);
    703   AH_trigger_curl ();
    704   return MHD_YES;
    705 }
    706 
    707 
    708 /**
    709  * Load encrypted keyshare from db and return it to the client.
    710  *
    711  * @param truth_uuid UUID to the truth for the looup
    712  * @param connection the connection to respond upon
    713  * @return MHD status code
    714  */
    715 static enum MHD_Result
    716 return_key_share (
    717   const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
    718   struct MHD_Connection *connection)
    719 {
    720   struct ANASTASIS_CRYPTO_EncryptedKeyShareP encrypted_keyshare;
    721 
    722   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    723               "Returning key share of %s\n",
    724               TALER_B2S (truth_uuid));
    725   {
    726     enum GNUNET_DB_QueryStatus qs;
    727 
    728     qs = ANASTASIS_DB_get_key_share (
    729       truth_uuid,
    730       &encrypted_keyshare);
    731     switch (qs)
    732     {
    733     case GNUNET_DB_STATUS_HARD_ERROR:
    734     case GNUNET_DB_STATUS_SOFT_ERROR:
    735       GNUNET_break (0);
    736       return TALER_MHD_reply_with_error (connection,
    737                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
    738                                          TALER_EC_GENERIC_DB_FETCH_FAILED,
    739                                          "get key share");
    740     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
    741       /* this should be "impossible", after all the
    742          client was able to solve the challenge!
    743          (Exception: we deleted the truth via GC
    744          just while the client was trying to recover.
    745          Alas, highly unlikely...) */
    746       GNUNET_break (0);
    747       return TALER_MHD_reply_with_error (connection,
    748                                          MHD_HTTP_NOT_FOUND,
    749                                          TALER_EC_ANASTASIS_TRUTH_KEY_SHARE_GONE,
    750                                          NULL);
    751     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
    752       break;
    753     }
    754   }
    755 
    756   {
    757     struct MHD_Response *resp;
    758     enum MHD_Result ret;
    759 
    760     resp = MHD_create_response_from_buffer (sizeof (encrypted_keyshare),
    761                                             &encrypted_keyshare,
    762                                             MHD_RESPMEM_MUST_COPY);
    763     TALER_MHD_add_global_headers (resp,
    764                                   false);
    765     ret = MHD_queue_response (connection,
    766                               MHD_HTTP_OK,
    767                               resp);
    768     MHD_destroy_response (resp);
    769     return ret;
    770   }
    771 }
    772 
    773 
    774 /**
    775  * Mark @a gc as suspended and update the respective
    776  * data structures and jobs.
    777  *
    778  * @param[in,out] gc context of the suspended operation
    779  */
    780 static void
    781 gc_suspended (struct SolveContext *gc)
    782 {
    783   GNUNET_assert (NULL == gc->hn);
    784   GNUNET_assert (! gc->suspended);
    785   gc->suspended = true;
    786   if (NULL == AH_to_heap)
    787     AH_to_heap = GNUNET_CONTAINER_heap_create (
    788       GNUNET_CONTAINER_HEAP_ORDER_MIN);
    789   gc->hn = GNUNET_CONTAINER_heap_insert (AH_to_heap,
    790                                          gc,
    791                                          gc->timeout.abs_value_us);
    792   if (NULL != to_task)
    793   {
    794     GNUNET_SCHEDULER_cancel (to_task);
    795     to_task = NULL;
    796   }
    797   {
    798     struct SolveContext *rn;
    799 
    800     rn = GNUNET_CONTAINER_heap_peek (AH_to_heap);
    801     to_task = GNUNET_SCHEDULER_add_at (rn->timeout,
    802                                        &do_timeout,
    803                                        NULL);
    804   }
    805 }
    806 
    807 
    808 /**
    809  * Run the authorization method-specific 'process' function and continue
    810  * based on its result with generating an HTTP response.
    811  *
    812  * @param connection the connection we are handling
    813  * @param gc our overall handler context
    814  */
    815 static enum MHD_Result
    816 run_authorization_process (struct MHD_Connection *connection,
    817                            struct SolveContext *gc)
    818 {
    819   enum ANASTASIS_AUTHORIZATION_SolveResult ret;
    820 
    821   GNUNET_assert (! gc->suspended);
    822   if (NULL == gc->authorization->solve)
    823   {
    824     GNUNET_break (0);
    825     return TALER_MHD_reply_with_error (gc->connection,
    826                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
    827                                        TALER_EC_ANASTASIS_TRUTH_AUTHORIZATION_START_FAILED,
    828                                        "solve method not implemented for authorization method");
    829   }
    830   ret = gc->authorization->solve (gc->as,
    831                                   gc->timeout,
    832                                   &gc->challenge_response,
    833                                   connection);
    834   switch (ret)
    835   {
    836   case ANASTASIS_AUTHORIZATION_SRES_SUSPENDED:
    837     /* connection was suspended */
    838     gc_suspended (gc);
    839     return MHD_YES;
    840   case ANASTASIS_AUTHORIZATION_SRES_FAILED:
    841     gc->authorization->cleanup (gc->as);
    842     gc->as = NULL;
    843     return MHD_YES;
    844   case ANASTASIS_AUTHORIZATION_SRES_FAILED_REPLY_FAILED:
    845     gc->authorization->cleanup (gc->as);
    846     gc->as = NULL;
    847     return MHD_NO;
    848   case ANASTASIS_AUTHORIZATION_SRES_FINISHED:
    849     GNUNET_assert (! gc->suspended);
    850     gc->authorization->cleanup (gc->as);
    851     gc->as = NULL;
    852     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    853                 "Resuming with authorization successful!\n");
    854     if (gc->in_list)
    855     {
    856       GNUNET_CONTAINER_DLL_remove (gc_head,
    857                                    gc_tail,
    858                                    gc);
    859       gc->in_list = false;
    860     }
    861     return MHD_YES;
    862   }
    863   GNUNET_break (0);
    864   return MHD_NO;
    865 }
    866 
    867 
    868 /**
    869  * Use the database to rate-limit queries to the authentication
    870  * procedure, but without actually storing 'real' challenge codes.
    871  *
    872  * @param[in,out] gc context to rate limit requests for
    873  * @return #GNUNET_OK if rate-limiting passes,
    874  *         #GNUNET_NO if a reply was sent (rate limited)
    875  *         #GNUNET_SYSERR if we failed and no reply
    876  *                        was queued
    877  */
    878 static enum GNUNET_GenericReturnValue
    879 rate_limit (struct SolveContext *gc)
    880 {
    881   enum GNUNET_DB_QueryStatus qs;
    882   struct GNUNET_TIME_Timestamp rt;
    883   uint64_t code;
    884   enum ANASTASIS_DB_CodeStatus cs;
    885   struct GNUNET_HashCode hc;
    886   bool satisfied;
    887   uint64_t dummy;
    888 
    889   rt = GNUNET_TIME_UNIT_FOREVER_TS;
    890   qs = ANASTASIS_DB_create_challenge_code (
    891     &gc->truth_uuid,
    892     MAX_QUESTION_FREQ,
    893     GNUNET_TIME_UNIT_HOURS,
    894     INITIAL_RETRY_COUNTER,
    895     &rt,
    896     &code);
    897   if (0 > qs)
    898   {
    899     GNUNET_break (0 < qs);
    900     return (MHD_YES ==
    901             TALER_MHD_reply_with_error (gc->connection,
    902                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
    903                                         TALER_EC_GENERIC_DB_FETCH_FAILED,
    904                                         "create_challenge_code (for rate limiting)"))
    905            ? GNUNET_NO
    906            : GNUNET_SYSERR;
    907   }
    908   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
    909   {
    910     return (MHD_YES ==
    911             reply_rate_limited (gc))
    912            ? GNUNET_NO
    913            : GNUNET_SYSERR;
    914   }
    915   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    916               "Using intentionally wrong answer to produce rate-limiting\n");
    917   /* decrement trial counter */
    918   ANASTASIS_hash_answer (code + 1,      /* always use wrong answer */
    919                          &hc);
    920   cs = ANASTASIS_DB_verify_challenge_code (
    921     &gc->truth_uuid,
    922     &hc,
    923     &dummy,
    924     &satisfied);
    925   switch (cs)
    926   {
    927   case ANASTASIS_DB_CODE_STATUS_CHALLENGE_CODE_MISMATCH:
    928     /* good, what we wanted */
    929     return GNUNET_OK;
    930   case ANASTASIS_DB_CODE_STATUS_HARD_ERROR:
    931   case ANASTASIS_DB_CODE_STATUS_SOFT_ERROR:
    932     GNUNET_break (0);
    933     return (MHD_YES ==
    934             TALER_MHD_reply_with_error (gc->connection,
    935                                         MHD_HTTP_INTERNAL_SERVER_ERROR,
    936                                         TALER_EC_GENERIC_DB_FETCH_FAILED,
    937                                         "verify_challenge_code"))
    938            ? GNUNET_NO
    939            : GNUNET_SYSERR;
    940   case ANASTASIS_DB_CODE_STATUS_NO_RESULTS:
    941     return (MHD_YES ==
    942             reply_rate_limited (gc))
    943            ? GNUNET_NO
    944            : GNUNET_SYSERR;
    945   case ANASTASIS_DB_CODE_STATUS_VALID_CODE_STORED:
    946     /* this should be impossible, we used code+1 */
    947     GNUNET_assert (0);
    948   }
    949   return GNUNET_SYSERR;
    950 }
    951 
    952 
    953 /**
    954  * Handle special case of a security question where we do not
    955  * generate a code. Rate limits answers against brute forcing.
    956  *
    957  * @param[in,out] gc request to handle
    958  * @param decrypted_truth hash to check against
    959  * @param decrypted_truth_size number of bytes in @a decrypted_truth
    960  * @return MHD status code
    961  */
    962 static enum MHD_Result
    963 handle_security_question (struct SolveContext *gc,
    964                           const void *decrypted_truth,
    965                           size_t decrypted_truth_size)
    966 {
    967   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    968               "Handling security question challenge\n");
    969   /* rate limit */
    970   {
    971     enum GNUNET_GenericReturnValue ret;
    972 
    973     ret = rate_limit (gc);
    974     if (GNUNET_OK != ret)
    975       return (GNUNET_NO == ret) ? MHD_YES : MHD_NO;
    976   }
    977   /* check reply matches truth */
    978   if ( (decrypted_truth_size != sizeof (struct GNUNET_HashCode)) ||
    979        (0 != memcmp (&gc->challenge_response,
    980                      decrypted_truth,
    981                      decrypted_truth_size)) )
    982   {
    983     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    984                 "Wrong answer provided to secure question had %u bytes, wanted %u\n",
    985                 (unsigned int) decrypted_truth_size,
    986                 (unsigned int) sizeof (struct GNUNET_HashCode));
    987     return TALER_MHD_reply_with_error (gc->connection,
    988                                        MHD_HTTP_FORBIDDEN,
    989                                        TALER_EC_ANASTASIS_TRUTH_CHALLENGE_FAILED,
    990                                        NULL);
    991   }
    992   /* good, return the key share */
    993   return return_key_share (&gc->truth_uuid,
    994                            gc->connection);
    995 }
    996 
    997 
    998 /**
    999  * Handle special case of an answer being directly checked by the
   1000  * plugin and not by our database.  Also ensures that the
   1001  * request is rate-limited.
   1002  *
   1003  * @param[in,out] gc request to handle
   1004  * @param decrypted_truth hash to check against
   1005  * @param decrypted_truth_size number of bytes in @a decrypted_truth
   1006  * @return MHD status code
   1007  */
   1008 static enum MHD_Result
   1009 direct_validation (struct SolveContext *gc,
   1010                    const void *decrypted_truth,
   1011                    size_t decrypted_truth_size)
   1012 {
   1013   /* Non-random code, call plugin directly! */
   1014   enum ANASTASIS_AUTHORIZATION_SolveResult aar;
   1015   enum GNUNET_GenericReturnValue ret;
   1016 
   1017   ret = rate_limit (gc);
   1018   if (GNUNET_OK != ret)
   1019     return (GNUNET_NO == ret) ? MHD_YES : MHD_NO;
   1020   gc->as = gc->authorization->start (gc->authorization->cls,
   1021                                      &AH_trigger_daemon,
   1022                                      NULL,
   1023                                      &gc->truth_uuid,
   1024                                      0LLU,
   1025                                      decrypted_truth,
   1026                                      decrypted_truth_size);
   1027   if (NULL == gc->as)
   1028   {
   1029     GNUNET_break (0);
   1030     return TALER_MHD_reply_with_error (gc->connection,
   1031                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
   1032                                        TALER_EC_ANASTASIS_TRUTH_AUTHORIZATION_START_FAILED,
   1033                                        NULL);
   1034   }
   1035   if (NULL == gc->authorization->solve)
   1036   {
   1037     GNUNET_break (0);
   1038     return TALER_MHD_reply_with_error (gc->connection,
   1039                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
   1040                                        TALER_EC_ANASTASIS_TRUTH_AUTHORIZATION_START_FAILED,
   1041                                        "solve method not implemented for authorization method");
   1042   }
   1043   aar = gc->authorization->solve (gc->as,
   1044                                   gc->timeout,
   1045                                   &gc->challenge_response,
   1046                                   gc->connection);
   1047   switch (aar)
   1048   {
   1049   case ANASTASIS_AUTHORIZATION_SRES_FAILED:
   1050     return MHD_YES;
   1051   case ANASTASIS_AUTHORIZATION_SRES_SUSPENDED:
   1052     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1053                 "Suspending request handling\n");
   1054     gc_suspended (gc);
   1055     return MHD_YES;
   1056   case ANASTASIS_AUTHORIZATION_SRES_FAILED_REPLY_FAILED:
   1057     return MHD_NO;
   1058   case ANASTASIS_AUTHORIZATION_SRES_FINISHED:
   1059     return return_key_share (&gc->truth_uuid,
   1060                              gc->connection);
   1061   }
   1062   GNUNET_break (0);
   1063   return MHD_NO;
   1064 }
   1065 
   1066 
   1067 /**
   1068  * Handle special case of an answer being checked
   1069  * by the plugin asynchronously (IBAN) after we inverted
   1070  * the hash using the database.
   1071  *
   1072  * @param[in,out] gc request to handle
   1073  * @param code validation code provided by the client
   1074  * @param decrypted_truth hash to check against
   1075  * @param decrypted_truth_size number of bytes in @a decrypted_truth
   1076  * @return MHD status code
   1077  */
   1078 static enum MHD_Result
   1079 iban_validation (struct SolveContext *gc,
   1080                  uint64_t code,
   1081                  const void *decrypted_truth,
   1082                  size_t decrypted_truth_size)
   1083 {
   1084   enum ANASTASIS_AUTHORIZATION_SolveResult aar;
   1085 
   1086   gc->as = gc->authorization->start (gc->authorization->cls,
   1087                                      &AH_trigger_daemon,
   1088                                      NULL,
   1089                                      &gc->truth_uuid,
   1090                                      code,
   1091                                      decrypted_truth,
   1092                                      decrypted_truth_size);
   1093   if (NULL == gc->as)
   1094   {
   1095     GNUNET_break (0);
   1096     return TALER_MHD_reply_with_error (gc->connection,
   1097                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
   1098                                        TALER_EC_ANASTASIS_TRUTH_AUTHORIZATION_START_FAILED,
   1099                                        NULL);
   1100   }
   1101   if (NULL == gc->authorization->solve)
   1102   {
   1103     GNUNET_break (0);
   1104     return TALER_MHD_reply_with_error (gc->connection,
   1105                                        MHD_HTTP_INTERNAL_SERVER_ERROR,
   1106                                        TALER_EC_ANASTASIS_TRUTH_AUTHORIZATION_START_FAILED,
   1107                                        "solve method not implemented for authorization method");
   1108   }
   1109   aar = gc->authorization->solve (gc->as,
   1110                                   gc->timeout,
   1111                                   &gc->challenge_response,
   1112                                   gc->connection);
   1113   switch (aar)
   1114   {
   1115   case ANASTASIS_AUTHORIZATION_SRES_FAILED:
   1116     return MHD_YES;
   1117   case ANASTASIS_AUTHORIZATION_SRES_SUSPENDED:
   1118     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1119                 "Suspending request handling\n");
   1120     gc_suspended (gc);
   1121     return MHD_YES;
   1122   case ANASTASIS_AUTHORIZATION_SRES_FAILED_REPLY_FAILED:
   1123     return MHD_NO;
   1124   case ANASTASIS_AUTHORIZATION_SRES_FINISHED:
   1125     return return_key_share (&gc->truth_uuid,
   1126                              gc->connection);
   1127   }
   1128   GNUNET_break (0);
   1129   return MHD_NO;
   1130 }
   1131 
   1132 
   1133 enum MHD_Result
   1134 AH_handler_truth_solve (
   1135   struct MHD_Connection *connection,
   1136   struct TM_HandlerContext *hc,
   1137   const struct ANASTASIS_CRYPTO_TruthUUIDP *truth_uuid,
   1138   const char *upload_data,
   1139   size_t *upload_data_size)
   1140 {
   1141   struct SolveContext *gc = hc->ctx;
   1142   void *encrypted_truth;
   1143   size_t encrypted_truth_size;
   1144   void *decrypted_truth;
   1145   size_t decrypted_truth_size;
   1146   char *truth_mime = NULL;
   1147   bool is_question;
   1148 
   1149   if (NULL == gc)
   1150   {
   1151     /* Fresh request, do initial setup */
   1152     gc = GNUNET_new (struct SolveContext);
   1153     gc->hc = hc;
   1154     hc->ctx = gc;
   1155     gc->connection = connection;
   1156     gc->truth_uuid = *truth_uuid;
   1157     gc->hc->cc = &request_done;
   1158     gc->timeout = GNUNET_TIME_relative_to_absolute (
   1159       GNUNET_TIME_UNIT_SECONDS);
   1160     TALER_MHD_parse_request_timeout (connection,
   1161                                      &gc->timeout);
   1162   } /* end of first-time initialization (if NULL == gc) */
   1163   else
   1164   {
   1165     /* might have been woken up by authorization plugin,
   1166        so clear the flag. MDH called us, so we are
   1167        clearly no longer suspended */
   1168     gc->suspended = false;
   1169     if (NULL != gc->resp)
   1170     {
   1171       enum MHD_Result ret;
   1172 
   1173       /* We generated a response asynchronously, queue that */
   1174       ret = MHD_queue_response (connection,
   1175                                 gc->response_code,
   1176                                 gc->resp);
   1177       GNUNET_break (MHD_YES == ret);
   1178       MHD_destroy_response (gc->resp);
   1179       gc->resp = NULL;
   1180       return ret;
   1181     }
   1182     if (NULL != gc->as)
   1183     {
   1184       /* Authorization process is "running", check what is going on */
   1185       GNUNET_assert (NULL != gc->authorization);
   1186       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1187                   "Continuing with running the authorization process\n");
   1188       GNUNET_assert (! gc->suspended);
   1189       return run_authorization_process (connection,
   1190                                         gc);
   1191     }
   1192     /* We get here if the async check for payment said this request
   1193        was indeed paid! */
   1194   }
   1195 
   1196   if (NULL == gc->root)
   1197   {
   1198     /* parse byte stream upload into JSON */
   1199     enum GNUNET_GenericReturnValue res;
   1200 
   1201     res = TALER_MHD_parse_post_json (connection,
   1202                                      &gc->opaque_post_parsing_context,
   1203                                      upload_data,
   1204                                      upload_data_size,
   1205                                      &gc->root);
   1206     if (GNUNET_SYSERR == res)
   1207     {
   1208       GNUNET_assert (NULL == gc->root);
   1209       return MHD_NO; /* bad upload, could not even generate error */
   1210     }
   1211     if ( (GNUNET_NO == res) ||
   1212          (NULL == gc->root) )
   1213     {
   1214       GNUNET_assert (NULL == gc->root);
   1215       return MHD_YES; /* so far incomplete upload or parser error */
   1216     }
   1217 
   1218     /* 'root' is now initialized, parse JSON body */
   1219     {
   1220       struct GNUNET_JSON_Specification spec[] = {
   1221         GNUNET_JSON_spec_fixed_auto ("truth_decryption_key",
   1222                                      &gc->truth_key),
   1223         GNUNET_JSON_spec_fixed_auto ("h_response",
   1224                                      &gc->challenge_response),
   1225         GNUNET_JSON_spec_mark_optional (
   1226           GNUNET_JSON_spec_fixed_auto ("payment_secret",
   1227                                        &gc->payment_identifier),
   1228           &gc->no_payment_identifier_provided),
   1229         GNUNET_JSON_spec_end ()
   1230       };
   1231       enum GNUNET_GenericReturnValue pres;
   1232 
   1233       pres = TALER_MHD_parse_json_data (connection,
   1234                                         gc->root,
   1235                                         spec);
   1236       if (GNUNET_SYSERR == pres)
   1237       {
   1238         GNUNET_break (0);
   1239         return MHD_NO; /* hard failure */
   1240       }
   1241       if (GNUNET_NO == pres)
   1242       {
   1243         GNUNET_break_op (0);
   1244         return MHD_YES; /* failure */
   1245       }
   1246       if (! gc->no_payment_identifier_provided)
   1247         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1248                     "Client provided payment identifier `%s'\n",
   1249                     TALER_B2S (&gc->payment_identifier));
   1250     }
   1251   }
   1252 
   1253   {
   1254     /* load encrypted truth from DB; we may do this repeatedly
   1255        while handling the same request, if payment was checked
   1256        asynchronously! */
   1257     enum GNUNET_DB_QueryStatus qs;
   1258     char *method;
   1259 
   1260     qs = ANASTASIS_DB_get_escrow_challenge (
   1261       &gc->truth_uuid,
   1262       &encrypted_truth,
   1263       &encrypted_truth_size,
   1264       &truth_mime,
   1265       &method);
   1266     switch (qs)
   1267     {
   1268     case GNUNET_DB_STATUS_HARD_ERROR:
   1269     case GNUNET_DB_STATUS_SOFT_ERROR:
   1270       GNUNET_break (0);
   1271       return TALER_MHD_reply_with_error (gc->connection,
   1272                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
   1273                                          TALER_EC_GENERIC_DB_FETCH_FAILED,
   1274                                          "get escrow challenge");
   1275     case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   1276       return TALER_MHD_reply_with_error (connection,
   1277                                          MHD_HTTP_NOT_FOUND,
   1278                                          TALER_EC_ANASTASIS_TRUTH_UNKNOWN,
   1279                                          NULL);
   1280     case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   1281       break;
   1282     }
   1283     is_question = (0 == strcmp ("question",
   1284                                 method));
   1285     if (! is_question)
   1286     {
   1287       gc->authorization
   1288         = ANASTASIS_authorization_plugin_load (method,
   1289                                                AH_cfg);
   1290       if (NULL == gc->authorization)
   1291       {
   1292         enum MHD_Result ret;
   1293 
   1294         ret = TALER_MHD_reply_with_error (
   1295           connection,
   1296           MHD_HTTP_INTERNAL_SERVER_ERROR,
   1297           TALER_EC_ANASTASIS_TRUTH_AUTHORIZATION_METHOD_NO_LONGER_SUPPORTED,
   1298           method);
   1299         GNUNET_free (encrypted_truth);
   1300         GNUNET_free (truth_mime);
   1301         GNUNET_free (method);
   1302         return ret;
   1303       }
   1304       gc->challenge_cost = gc->authorization->cost;
   1305     }
   1306     else
   1307     {
   1308       gc->challenge_cost = AH_question_cost;
   1309     }
   1310     GNUNET_free (method);
   1311   }
   1312 
   1313   /* check for payment */
   1314   if ( (is_question) ||
   1315        (! gc->authorization->payment_plugin_managed) )
   1316   {
   1317     if (! TALER_amount_is_zero (&gc->challenge_cost))
   1318     {
   1319       /* Check database to see if the transaction is paid for */
   1320       enum GNUNET_DB_QueryStatus qs;
   1321       bool paid;
   1322 
   1323       if (gc->no_payment_identifier_provided)
   1324       {
   1325         GNUNET_free (truth_mime);
   1326         GNUNET_free (encrypted_truth);
   1327         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1328                     "Beginning payment, client did not provide payment identifier\n");
   1329         return begin_payment (gc);
   1330       }
   1331       qs = ANASTASIS_DB_check_challenge_payment (
   1332         &gc->payment_identifier,
   1333         &gc->truth_uuid,
   1334         &paid);
   1335       switch (qs)
   1336       {
   1337       case GNUNET_DB_STATUS_HARD_ERROR:
   1338       case GNUNET_DB_STATUS_SOFT_ERROR:
   1339         GNUNET_break (0);
   1340         GNUNET_free (truth_mime);
   1341         GNUNET_free (encrypted_truth);
   1342         return TALER_MHD_reply_with_error (gc->connection,
   1343                                            MHD_HTTP_INTERNAL_SERVER_ERROR,
   1344                                            TALER_EC_GENERIC_DB_FETCH_FAILED,
   1345                                            "check challenge payment");
   1346       case GNUNET_DB_STATUS_SUCCESS_NO_RESULTS:
   1347         /* Create fresh payment identifier (cannot trust client) */
   1348         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1349                     "Client-provided payment identifier is unknown.\n");
   1350         GNUNET_free (truth_mime);
   1351         GNUNET_free (encrypted_truth);
   1352         return begin_payment (gc);
   1353       case GNUNET_DB_STATUS_SUCCESS_ONE_RESULT:
   1354         if (! paid)
   1355         {
   1356           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1357                       "Payment identifier known. Checking payment with client's payment identifier\n");
   1358           GNUNET_free (truth_mime);
   1359           GNUNET_free (encrypted_truth);
   1360           return begin_payment (gc);
   1361         }
   1362         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1363                     "Payment confirmed\n");
   1364         break;
   1365       }
   1366     }
   1367     else
   1368     {
   1369       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1370                   "Request is free of charge\n");
   1371     }
   1372   }
   1373 
   1374   /* We've been paid, now validate the response */
   1375   /* decrypt encrypted_truth */
   1376   ANASTASIS_CRYPTO_truth_decrypt (&gc->truth_key,
   1377                                   encrypted_truth,
   1378                                   encrypted_truth_size,
   1379                                   &decrypted_truth,
   1380                                   &decrypted_truth_size);
   1381   GNUNET_free (encrypted_truth);
   1382   if (NULL == decrypted_truth)
   1383   {
   1384     /* most likely, the decryption key is simply wrong */
   1385     GNUNET_break_op (0);
   1386     GNUNET_free (truth_mime);
   1387     return TALER_MHD_reply_with_error (connection,
   1388                                        MHD_HTTP_BAD_REQUEST,
   1389                                        TALER_EC_ANASTASIS_TRUTH_DECRYPTION_FAILED,
   1390                                        NULL);
   1391   }
   1392 
   1393   /* Special case for secure question: we do not generate a numeric challenge,
   1394      but check that the hash matches */
   1395   if (is_question)
   1396   {
   1397     enum MHD_Result ret;
   1398 
   1399     ret = handle_security_question (gc,
   1400                                     decrypted_truth,
   1401                                     decrypted_truth_size);
   1402     GNUNET_free (truth_mime);
   1403     GNUNET_free (decrypted_truth);
   1404     return ret;
   1405   }
   1406 
   1407   /* Not security question, check for answer in DB */
   1408   {
   1409     enum ANASTASIS_DB_CodeStatus cs;
   1410     bool satisfied = false;
   1411     uint64_t code;
   1412 
   1413     GNUNET_free (truth_mime);
   1414     if (gc->authorization->user_provided_code)
   1415     {
   1416       enum MHD_Result res;
   1417 
   1418       if (GNUNET_TIME_absolute_is_past (gc->timeout))
   1419       {
   1420         GNUNET_free (decrypted_truth);
   1421         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1422                     "Timeout with user provided code\n");
   1423         return TALER_MHD_reply_with_error (connection,
   1424                                            MHD_HTTP_FORBIDDEN,
   1425                                            TALER_EC_ANASTASIS_IBAN_MISSING_TRANSFER,
   1426                                            "timeout awaiting validation");
   1427       }
   1428       res = direct_validation (gc,
   1429                                decrypted_truth,
   1430                                decrypted_truth_size);
   1431       GNUNET_free (decrypted_truth);
   1432       return res;
   1433     }
   1434 
   1435     /* random code, check against database */
   1436     cs = ANASTASIS_DB_verify_challenge_code (
   1437       &gc->truth_uuid,
   1438       &gc->challenge_response,
   1439       &code,
   1440       &satisfied);
   1441     switch (cs)
   1442     {
   1443     case ANASTASIS_DB_CODE_STATUS_CHALLENGE_CODE_MISMATCH:
   1444       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1445                   "Provided response does not match our stored challenge\n");
   1446       GNUNET_free (decrypted_truth);
   1447       return TALER_MHD_reply_with_error (connection,
   1448                                          MHD_HTTP_FORBIDDEN,
   1449                                          TALER_EC_ANASTASIS_TRUTH_CHALLENGE_FAILED,
   1450                                          NULL);
   1451     case ANASTASIS_DB_CODE_STATUS_HARD_ERROR:
   1452     case ANASTASIS_DB_CODE_STATUS_SOFT_ERROR:
   1453       GNUNET_break (0);
   1454       GNUNET_free (decrypted_truth);
   1455       return TALER_MHD_reply_with_error (gc->connection,
   1456                                          MHD_HTTP_INTERNAL_SERVER_ERROR,
   1457                                          TALER_EC_GENERIC_DB_FETCH_FAILED,
   1458                                          "verify_challenge_code");
   1459     case ANASTASIS_DB_CODE_STATUS_NO_RESULTS:
   1460       GNUNET_free (decrypted_truth);
   1461       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1462                   "Specified challenge code %s was not issued\n",
   1463                   GNUNET_h2s (&gc->challenge_response));
   1464       return TALER_MHD_reply_with_error (connection,
   1465                                          MHD_HTTP_FORBIDDEN,
   1466                                          TALER_EC_ANASTASIS_TRUTH_CHALLENGE_UNKNOWN,
   1467                                          "specific challenge code was not issued");
   1468     case ANASTASIS_DB_CODE_STATUS_VALID_CODE_STORED:
   1469       if (! satisfied)
   1470       {
   1471         enum MHD_Result res;
   1472 
   1473         res = iban_validation (gc,
   1474                                code,
   1475                                decrypted_truth,
   1476                                decrypted_truth_size);
   1477         GNUNET_free (decrypted_truth);
   1478         return res;
   1479       }
   1480       GNUNET_free (decrypted_truth);
   1481       return return_key_share (&gc->truth_uuid,
   1482                                connection);
   1483     default:
   1484       GNUNET_break (0);
   1485       return MHD_NO;
   1486     }
   1487   }
   1488 }