implement logic to check protocol version compatibility (#5035)

This commit is contained in:
Christian Grothoff 2017-07-01 14:15:26 +02:00
parent f048de9782
commit d77c4160ec
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
4 changed files with 109 additions and 7 deletions

View File

@ -1234,10 +1234,12 @@ build_refresh ()
* *
* @param cls closure * @param cls closure
* @param _keys information about keys of the exchange * @param _keys information about keys of the exchange
* @param vc compatibility information
*/ */
static void static void
cert_cb (void *cls, 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 */ /* check that keys is OK */
if (NULL == _keys) if (NULL == _keys)

View File

@ -29,6 +29,17 @@
#include "taler_signatures.h" #include "taler_signatures.h"
#include "exchange_api_handle.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. * 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[in] resp_obj JSON object to parse
* @param[out] key_data where to store the results we decoded * @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) * @return #GNUNET_OK on success, #GNUNET_SYSERR on error (malformed JSON)
*/ */
static int static int
decode_keys_json (const json_t *resp_obj, 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 GNUNET_TIME_Absolute list_issue_date;
struct TALER_ExchangeSignatureP sig; 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 */ /* parse the master public key and issue date of the response */
{ {
const char *ver; const char *ver;
unsigned int age;
unsigned int revision;
unsigned int current;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_string ("version", GNUNET_JSON_spec_string ("version",
&ver), &ver),
@ -526,6 +542,29 @@ decode_keys_json (const json_t *resp_obj,
GNUNET_JSON_parse (resp_obj, GNUNET_JSON_parse (resp_obj,
spec, spec,
NULL, NULL)); NULL, NULL));
if (3 != sscanf (ver,
"%u:%u:%u",
&current,
&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); 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_Handle *exchange = kr->exchange;
struct TALER_EXCHANGE_Keys kd; struct TALER_EXCHANGE_Keys kd;
struct TALER_EXCHANGE_Keys kd_old; struct TALER_EXCHANGE_Keys kd_old;
enum TALER_EXCHANGE_VersionCompatibility vc;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received keys from URL `%s' with status %ld.\n", "Received keys from URL `%s' with status %ld.\n",
kr->url, kr->url,
response_code); response_code);
kd_old = exchange->key_data; kd_old = exchange->key_data;
vc = TALER_EXCHANGE_VC_PROTOCOL_ERROR;
switch (response_code) switch (response_code)
{ {
case 0: case 0:
@ -725,7 +766,8 @@ keys_completed_cb (void *cls,
} }
if (GNUNET_OK != if (GNUNET_OK !=
decode_keys_json (resp_obj, decode_keys_json (resp_obj,
&kd)) &kd,
&vc))
{ {
response_code = 0; response_code = 0;
break; break;
@ -748,7 +790,8 @@ keys_completed_cb (void *cls,
exchange->state = MHS_FAILED; exchange->state = MHS_FAILED;
/* notify application that we failed */ /* notify application that we failed */
exchange->cert_cb (exchange->cert_cb_cls, exchange->cert_cb (exchange->cert_cb_cls,
NULL); NULL,
vc);
if (NULL != exchange->key_data_raw) if (NULL != exchange->key_data_raw)
{ {
json_decref (exchange->key_data_raw); json_decref (exchange->key_data_raw);
@ -764,7 +807,8 @@ keys_completed_cb (void *cls,
exchange->state = MHS_CERT; exchange->state = MHS_CERT;
/* notify application about the key information */ /* notify application about the key information */
exchange->cert_cb (exchange->cert_cb_cls, exchange->cert_cb (exchange->cert_cb_cls,
&exchange->key_data); &exchange->key_data,
vc);
free_key_data (&kd_old); free_key_data (&kd_old);
} }

View File

@ -3050,10 +3050,12 @@ do_shutdown (void *cls)
* *
* @param cls closure * @param cls closure
* @param keys information about keys of the exchange * @param keys information about keys of the exchange
* @param vc version compatibility
*/ */
static void static void
cert_cb (void *cls, 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; struct InterpreterState *is = cls;

View File

@ -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 * Function called with information about who is auditing
* a particular exchange and what key the exchange is using. * a particular exchange and what key the exchange is using.
@ -237,10 +289,12 @@ struct TALER_EXCHANGE_Keys
* @param cls closure * @param cls closure
* @param keys information about the various keys used * @param keys information about the various keys used
* by the exchange, NULL if /keys failed * by the exchange, NULL if /keys failed
* @param compat protocol compatibility information
*/ */
typedef void typedef void
(*TALER_EXCHANGE_CertificationCallback) (void *cls, (*TALER_EXCHANGE_CertificationCallback) (void *cls,
const struct TALER_EXCHANGE_Keys *keys); const struct TALER_EXCHANGE_Keys *keys,
enum TALER_EXCHANGE_VersionCompatibility compat);
/** /**