diff options
Diffstat (limited to 'src/authorization/anastasis_authorization_plugin_totp.c')
-rw-r--r-- | src/authorization/anastasis_authorization_plugin_totp.c | 87 |
1 files changed, 46 insertions, 41 deletions
diff --git a/src/authorization/anastasis_authorization_plugin_totp.c b/src/authorization/anastasis_authorization_plugin_totp.c index 6fcdd39..c127e38 100644 --- a/src/authorization/anastasis_authorization_plugin_totp.c +++ b/src/authorization/anastasis_authorization_plugin_totp.c @@ -3,7 +3,7 @@ Copyright (C) 2021 Anastasis SARL Anastasis is free software; you can redistribute it and/or modify it under the - terms of the GNU Lesser General Public License as published by the Free Software + terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. Anastasis is distributed in the hope that it will be useful, but WITHOUT ANY @@ -59,14 +59,14 @@ struct ANASTASIS_AUTHORIZATION_State struct ANASTASIS_CRYPTO_TruthUUIDP truth_uuid; /** - * Our context. + * Was the challenge satisfied? */ - const struct ANASTASIS_AuthorizationContext *ac; + struct GNUNET_HashCode valid_replies[TIME_INTERVAL_RANGE * 2 + 1]; /** - * Was the challenge satisfied? + * Our context. */ - bool ok; + const struct ANASTASIS_AuthorizationContext *ac; }; @@ -103,7 +103,7 @@ totp_validate (void *cls, GNUNET_break_op (0); if (MHD_NO == TALER_MHD_reply_with_error (connection, - MHD_HTTP_EXPECTATION_FAILED, + MHD_HTTP_CONFLICT, TALER_EC_ANASTASIS_TOTP_KEY_MISSING, NULL)) return GNUNET_SYSERR; @@ -114,7 +114,7 @@ totp_validate (void *cls, GNUNET_break_op (0); if (MHD_NO == TALER_MHD_reply_with_error (connection, - MHD_HTTP_EXPECTATION_FAILED, + MHD_HTTP_CONFLICT, TALER_EC_ANASTASIS_TOTP_KEY_INVALID, NULL)) return GNUNET_SYSERR; @@ -141,7 +141,7 @@ compute_totp (int time_off, struct GNUNET_TIME_Absolute now; time_t t; uint64_t ctr; - uint8_t hmac[16]; /* SHA1: 16 bytes */ + uint8_t hmac[20]; /* SHA1: 20 bytes */ now = GNUNET_TIME_absolute_get (); while (time_off < 0) @@ -184,21 +184,14 @@ compute_totp (int time_off, { uint32_t code = 0; + int offset; + offset = hmac[sizeof (hmac) - 1] & 0x0f; for (int count = 0; count < 4; count++) - code += hmac[(hmac[sizeof (hmac) - 1] & 0x0f) + 3 - count] << 8 * count; + code |= ((uint32_t) hmac[offset + 3 - count]) << (8 * count); code &= 0x7fffffff; - -#if VAR_DIGITS - if (digits == 6) - code = code % 1000000; - else if (digits == 7) - code = code % 10000000; - else if (digits == 8) - code = code % 100000000; -#else - code = code % 1000000; -#endif + /* always use 8 digits (maximum) */ + code = code % 100000000; return code; } } @@ -212,9 +205,9 @@ compute_totp (int time_off, * @param trigger_cls closure for @a trigger * @param truth_uuid Identifier of the challenge, to be (if possible) included in the * interaction with the user - * @param code set to secret code that the user provided to satisfy the challenge in - * the main anastasis protocol - * @param data input to validate (i.e. the shared secret) + * @param code always 0 (direct validation, backend does + * not generate a code in this mode) + * @param data truth for input to validate (i.e. the shared secret) * @param data_length number of bytes in @a data * @return state to track progress on the authorization operation, NULL on failure */ @@ -230,43 +223,50 @@ totp_start (void *cls, const struct ANASTASIS_AuthorizationContext *ac = cls; struct ANASTASIS_AUTHORIZATION_State *as; uint64_t want; + unsigned int off = 0; + GNUNET_assert (0 == code); as = GNUNET_new (struct ANASTASIS_AUTHORIZATION_State); as->ac = ac; as->truth_uuid = *truth_uuid; for (int i = -TIME_INTERVAL_RANGE; - i < TIME_INTERVAL_RANGE; + i <= TIME_INTERVAL_RANGE; i++) { want = compute_totp (i, data, data_length); - if (code == want) - as->ok = true; + ANASTASIS_hash_answer (want, + &as->valid_replies[off++]); } return as; } /** - * Begin issuing authentication challenge to user based on @a data. + * Check authentication response from the user. * * @param as authorization state * @param timeout how long do we have to produce a reply + * @param challenge_response hash of the response * @param connection HTTP client request (for queuing response, such as redirection to video portal) * @return state of the request */ -static enum ANASTASIS_AUTHORIZATION_Result -totp_process (struct ANASTASIS_AUTHORIZATION_State *as, - struct GNUNET_TIME_Absolute timeout, - struct MHD_Connection *connection) +static enum ANASTASIS_AUTHORIZATION_SolveResult +totp_solve (struct ANASTASIS_AUTHORIZATION_State *as, + struct GNUNET_TIME_Absolute timeout, + const struct GNUNET_HashCode *challenge_response, + struct MHD_Connection *connection) { MHD_RESULT mres; const char *mime; const char *lang; - if (as->ok) - return ANASTASIS_AUTHORIZATION_RES_FINISHED; + for (unsigned int i = 0; i<=TIME_INTERVAL_RANGE * 2; i++) + if (0 == + GNUNET_memcmp (challenge_response, + &as->valid_replies[i])) + return ANASTASIS_AUTHORIZATION_SRES_FINISHED; mime = MHD_lookup_connection_value (connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_ACCEPT); @@ -281,15 +281,20 @@ totp_process (struct ANASTASIS_AUTHORIZATION_State *as, /* Build HTTP response */ { struct MHD_Response *resp; - struct GNUNET_TIME_Absolute now; + struct GNUNET_TIME_Timestamp now; - now = GNUNET_TIME_absolute_get (); + now = GNUNET_TIME_timestamp_get (); if (TALER_MHD_xmime_matches (mime, "application/json")) { resp = TALER_MHD_MAKE_JSON_PACK ( - GNUNET_JSON_pack_time_abs ("server_time", - now)); + GNUNET_JSON_pack_uint64 ("code", + TALER_EC_ANASTASIS_TRUTH_CHALLENGE_FAILED), + GNUNET_JSON_pack_string ("hint", + TALER_ErrorCode_get_hint ( + TALER_EC_ANASTASIS_TRUTH_CHALLENGE_FAILED)), + GNUNET_JSON_pack_timestamp ("server_time", + now)); } else { @@ -300,7 +305,7 @@ totp_process (struct ANASTASIS_AUTHORIZATION_State *as, response_size = GNUNET_asprintf (&response, "Server time: %s", - GNUNET_STRINGS_absolute_time_to_string (now)); + GNUNET_TIME_timestamp2s (now)); resp = MHD_create_response_from_buffer (response_size, response, MHD_RESPMEM_MUST_COPY); @@ -316,8 +321,8 @@ totp_process (struct ANASTASIS_AUTHORIZATION_State *as, MHD_destroy_response (resp); } if (MHD_YES != mres) - return ANASTASIS_AUTHORIZATION_RES_SUCCESS_REPLY_FAILED; - return ANASTASIS_AUTHORIZATION_RES_SUCCESS; + return ANASTASIS_AUTHORIZATION_SRES_FAILED_REPLY_FAILED; + return ANASTASIS_AUTHORIZATION_SRES_FAILED; } @@ -354,7 +359,7 @@ libanastasis_plugin_authorization_totp_init (void *cls) plugin->code_retransmission_frequency = plugin->code_validity_period; plugin->validate = &totp_validate; plugin->start = &totp_start; - plugin->process = &totp_process; + plugin->solve = &totp_solve; plugin->cleanup = &totp_cleanup; return plugin; } |