From d77c4160ecf7b1d33d49ba47e3236f5dcc14ecc8 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Sat, 1 Jul 2017 14:15:26 +0200 Subject: implement logic to check protocol version compatibility (#5035) --- src/benchmark/taler-exchange-benchmark.c | 4 ++- src/exchange-lib/exchange_api_handle.c | 52 ++++++++++++++++++++++++++--- src/exchange-lib/test_exchange_api.c | 4 ++- src/include/taler_exchange_service.h | 56 +++++++++++++++++++++++++++++++- 4 files changed, 109 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/benchmark/taler-exchange-benchmark.c b/src/benchmark/taler-exchange-benchmark.c index 70cc014e7..10a5eed1b 100644 --- a/src/benchmark/taler-exchange-benchmark.c +++ b/src/benchmark/taler-exchange-benchmark.c @@ -1234,10 +1234,12 @@ build_refresh () * * @param cls closure * @param _keys information about keys of the exchange + * @param vc compatibility information */ static void cert_cb (void *cls, - const struct TALER_EXCHANGE_Keys *_keys) + const struct TALER_EXCHANGE_Keys *_keys, + enum TALER_EXCHANGE_VersionCompatibility vc) { /* check that keys is OK */ if (NULL == _keys) diff --git a/src/exchange-lib/exchange_api_handle.c b/src/exchange-lib/exchange_api_handle.c index 96ae45b37..a03f7d4ba 100644 --- a/src/exchange-lib/exchange_api_handle.c +++ b/src/exchange-lib/exchange_api_handle.c @@ -29,6 +29,17 @@ #include "taler_signatures.h" #include "exchange_api_handle.h" +/** + * Which revision of the Taler protocol is implemented + * by this library? Used to determine compatibility. + */ +#define TALER_PROTOCOL_CURRENT 0 + +/** + * How many revisions back are we compatible to? + */ +#define TALER_PROTOCOL_AGE 0 + /** * Log error related to CURL operations. @@ -485,11 +496,13 @@ parse_json_auditor (struct TALER_EXCHANGE_AuditorInformation *auditor, * * @param[in] resp_obj JSON object to parse * @param[out] key_data where to store the results we decoded + * @param[out] where to store version compatibility data * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (malformed JSON) */ static int decode_keys_json (const json_t *resp_obj, - struct TALER_EXCHANGE_Keys *key_data) + struct TALER_EXCHANGE_Keys *key_data, + enum TALER_EXCHANGE_VersionCompatibility *vc) { struct GNUNET_TIME_Absolute list_issue_date; struct TALER_ExchangeSignatureP sig; @@ -508,6 +521,9 @@ decode_keys_json (const json_t *resp_obj, /* parse the master public key and issue date of the response */ { const char *ver; + unsigned int age; + unsigned int revision; + unsigned int current; struct GNUNET_JSON_Specification spec[] = { GNUNET_JSON_spec_string ("version", &ver), @@ -526,6 +542,29 @@ decode_keys_json (const json_t *resp_obj, GNUNET_JSON_parse (resp_obj, spec, NULL, NULL)); + if (3 != sscanf (ver, + "%u:%u:%u", + ¤t, + &revision, + &age)) + { + GNUNET_break_op (0); + GNUNET_CRYPTO_hash_context_abort (hash_context); + return GNUNET_SYSERR; + } + *vc = TALER_EXCHANGE_VC_MATCH; + if (TALER_PROTOCOL_CURRENT < current) + { + *vc |= TALER_EXCHANGE_VC_NEWER; + if (TALER_PROTOCOL_CURRENT < current - age) + *vc |= TALER_EXCHANGE_VC_INCOMPATIBLE; + } + if (TALER_PROTOCOL_CURRENT > current) + { + *vc |= TALER_EXCHANGE_VC_OLDER; + if (TALER_PROTOCOL_CURRENT - TALER_PROTOCOL_AGE > current) + *vc |= TALER_EXCHANGE_VC_INCOMPATIBLE; + } key_data->version = GNUNET_strdup (ver); } @@ -707,12 +746,14 @@ keys_completed_cb (void *cls, struct TALER_EXCHANGE_Handle *exchange = kr->exchange; struct TALER_EXCHANGE_Keys kd; struct TALER_EXCHANGE_Keys kd_old; + enum TALER_EXCHANGE_VersionCompatibility vc; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received keys from URL `%s' with status %ld.\n", kr->url, response_code); kd_old = exchange->key_data; + vc = TALER_EXCHANGE_VC_PROTOCOL_ERROR; switch (response_code) { case 0: @@ -725,7 +766,8 @@ keys_completed_cb (void *cls, } if (GNUNET_OK != decode_keys_json (resp_obj, - &kd)) + &kd, + &vc)) { response_code = 0; break; @@ -748,7 +790,8 @@ keys_completed_cb (void *cls, exchange->state = MHS_FAILED; /* notify application that we failed */ exchange->cert_cb (exchange->cert_cb_cls, - NULL); + NULL, + vc); if (NULL != exchange->key_data_raw) { json_decref (exchange->key_data_raw); @@ -764,7 +807,8 @@ keys_completed_cb (void *cls, exchange->state = MHS_CERT; /* notify application about the key information */ exchange->cert_cb (exchange->cert_cb_cls, - &exchange->key_data); + &exchange->key_data, + vc); free_key_data (&kd_old); } diff --git a/src/exchange-lib/test_exchange_api.c b/src/exchange-lib/test_exchange_api.c index 24b8f7e20..b5b68041e 100644 --- a/src/exchange-lib/test_exchange_api.c +++ b/src/exchange-lib/test_exchange_api.c @@ -3050,10 +3050,12 @@ do_shutdown (void *cls) * * @param cls closure * @param keys information about keys of the exchange + * @param vc version compatibility */ static void cert_cb (void *cls, - const struct TALER_EXCHANGE_Keys *keys) + const struct TALER_EXCHANGE_Keys *keys, + enum TALER_EXCHANGE_VersionCompatibility vc) { struct InterpreterState *is = cls; diff --git a/src/include/taler_exchange_service.h b/src/include/taler_exchange_service.h index 04fa51fff..487304c59 100644 --- a/src/include/taler_exchange_service.h +++ b/src/include/taler_exchange_service.h @@ -230,6 +230,58 @@ struct TALER_EXCHANGE_Keys }; +/** + * How compatible are the protocol version of the exchange and this + * client? The bits (1,2,4) can be used to test if the exchange's + * version is incompatible, older or newer respectively. + */ +enum TALER_EXCHANGE_VersionCompatibility +{ + + /** + * The exchange runs exactly the same protocol version. + */ + TALER_EXCHANGE_VC_MATCH = 0, + + /** + * The exchange is too old or too new to be compatible with this + * implementation (bit) + */ + TALER_EXCHANGE_VC_INCOMPATIBLE = 1, + + /** + * The exchange is older than this implementation (bit) + */ + TALER_EXCHANGE_VC_OLDER = 2, + + /** + * The exchange is too old to be compatible with + * this implementation. + */ + TALER_EXCHANGE_VC_INCOMPATIBLE_OUTDATED + = TALER_EXCHANGE_VC_INCOMPATIBLE + | TALER_EXCHANGE_VC_OLDER, + + /** + * The exchange is more recent than this implementation (bit). + */ + TALER_EXCHANGE_VC_NEWER = 4, + + /** + * The exchange is too recent for this implementation. + */ + TALER_EXCHANGE_VC_INCOMPATIBLE_NEWER + = TALER_EXCHANGE_VC_INCOMPATIBLE + | TALER_EXCHANGE_VC_NEWER, + + /** + * We could not even parse the version data. + */ + TALER_EXCHANGE_VC_PROTOCOL_ERROR = 8 + +}; + + /** * Function called with information about who is auditing * a particular exchange and what key the exchange is using. @@ -237,10 +289,12 @@ struct TALER_EXCHANGE_Keys * @param cls closure * @param keys information about the various keys used * by the exchange, NULL if /keys failed + * @param compat protocol compatibility information */ typedef void (*TALER_EXCHANGE_CertificationCallback) (void *cls, - const struct TALER_EXCHANGE_Keys *keys); + const struct TALER_EXCHANGE_Keys *keys, + enum TALER_EXCHANGE_VersionCompatibility compat); /** -- cgit v1.2.3