Logic for extensions more generic

- signature of the hash of the json will be checked
- config_verify for signature check of any extension
- FP for parsing the config as and converting to JSON
- simplify TEH_handler_management_post_extensions
- cleanups
This commit is contained in:
Özgür Kesim 2021-12-29 16:08:45 +01:00
parent 128d136885
commit 75763f2823
Signed by: oec
GPG Key ID: 3D76A56D79EDD9D7
12 changed files with 337 additions and 291 deletions

View File

@ -150,19 +150,33 @@ bool TEH_suicide;
/** /**
* The global manifest with the list supported extensions, sorted by * The global manifest with the list supported extensions, sorted by
* TALER_Extension_Type. * TALER_Extension_Type.
*
* TODO: This needs to become a dynamic list, once we have a model for
* extensions as plugins.
**/ **/
const struct TALER_Extension TEH_extensions[TALER_Extension_Max] = { const struct TALER_Extension TEH_extensions[] = {
[TALER_Extension_AgeRestriction] = {
.type = TALER_Extension_AgeRestriction,
.name = "age_restriction",
.critical = false,
.config = NULL, // disabled per default
/* TODO:
.parse_config = &TALER_Extension_AgeRestriction_parse_config,
.config_to_json = &TALER_Extension_AgeRestriction_config_to_json,
*/
},
[TALER_Extension_Peer2Peer] = { [TALER_Extension_Peer2Peer] = {
.type = TALER_Extension_Peer2Peer, .type = TALER_Extension_Peer2Peer,
.name = "peer2peer", .name = "peer2peer",
.critical = false, .critical = false,
.config = NULL, // disabled per default .config = NULL, // disabled per default
}, },
[TALER_Extension_AgeRestriction] = { /* terminator */
.type = TALER_Extension_AgeRestriction, [TALER_Extension_Max] = {
.name = "age_restriction", .type = TALER_Extension_Max,
.name = NULL,
.critical = false, .critical = false,
.config = NULL, // disabled per default .config = NULL,
}, },
}; };

View File

@ -202,9 +202,9 @@ extern volatile bool MHD_terminating;
extern struct GNUNET_CURL_Context *TEH_curl_ctx; extern struct GNUNET_CURL_Context *TEH_curl_ctx;
/** /**
* The manifest of the available extensions * The manifest of the available extensions, NULL terminated
*/ */
extern const struct TALER_Extension TEH_extensions[TALER_Extension_Max]; extern const struct TALER_Extension TEH_extensions[];
/** /**
* @brief Struct describing an URL and the handler for it. * @brief Struct describing an URL and the handler for it.

View File

@ -32,19 +32,14 @@
#include "taler_dbevents.h" #include "taler_dbevents.h"
/**
* Extension carries the necessary data for a particular extension.
*
*/
struct Extension struct Extension
{ {
enum TALER_Extension_Type type; enum TALER_Extension_Type type;
json_t *config_json; json_t *config;
// This union contains the parsed configuration for each extension.
union
{
// configuration for the age restriction
struct TALER_AgeMask mask;
/* TODO oec - add peer2peer config */
};
}; };
/** /**
@ -57,6 +52,38 @@ struct SetExtensionsContext
struct TALER_MasterSignatureP *extensions_sigs; struct TALER_MasterSignatureP *extensions_sigs;
}; };
/**
* @brief verifies the signature a configuration with the offline master key.
*
* @param config configuration of an extension given as JSON object
* @param master_priv offline master public key of the exchange
* @param[out] master_sig signature
* @return GNUNET_OK on success, GNUNET_SYSERR otherwise
*/
static enum GNUNET_GenericReturnValue
config_verify (
const json_t *config,
const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_MasterSignatureP *master_sig
)
{
enum GNUNET_GenericReturnValue ret;
struct TALER_ExtensionConfigHash h_config;
ret = TALER_extension_config_hash (config, &h_config);
if (GNUNET_OK != ret)
{
GNUNET_break (0);
return ret;
}
return TALER_exchange_offline_extension_config_hash_verify (h_config,
master_pub,
master_sig);
}
/** /**
* Function implementing database transaction to set the configuration of * Function implementing database transaction to set the configuration of
* extensions. It runs the transaction logic. * extensions. It runs the transaction logic.
@ -88,7 +115,7 @@ set_extensions (void *cls,
enum GNUNET_DB_QueryStatus qs; enum GNUNET_DB_QueryStatus qs;
char *config; char *config;
config = json_dumps (ext->config_json, JSON_COMPACT | JSON_SORT_KEYS); config = json_dumps (ext->config, JSON_COMPACT | JSON_SORT_KEYS);
if (NULL == config) if (NULL == config)
{ {
GNUNET_break (0); GNUNET_break (0);
@ -143,7 +170,7 @@ TEH_handler_management_post_extensions (
struct SetExtensionsContext sec = {0}; struct SetExtensionsContext sec = {0};
json_t *extensions; json_t *extensions;
json_t *extensions_sigs; json_t *extensions_sigs;
struct GNUNET_JSON_Specification spec[] = { struct GNUNET_JSON_Specification top_spec[] = {
GNUNET_JSON_spec_json ("extensions", GNUNET_JSON_spec_json ("extensions",
&extensions), &extensions),
GNUNET_JSON_spec_json ("extensions_sigs", GNUNET_JSON_spec_json ("extensions_sigs",
@ -157,7 +184,7 @@ TEH_handler_management_post_extensions (
res = TALER_MHD_parse_json_data (connection, res = TALER_MHD_parse_json_data (connection,
root, root,
spec); top_spec);
if (GNUNET_SYSERR == res) if (GNUNET_SYSERR == res)
return MHD_NO; /* hard failure */ return MHD_NO; /* hard failure */
if (GNUNET_NO == res) if (GNUNET_NO == res)
@ -168,7 +195,7 @@ TEH_handler_management_post_extensions (
json_is_array (extensions_sigs)) ) json_is_array (extensions_sigs)) )
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (top_spec);
return TALER_MHD_reply_with_error ( return TALER_MHD_reply_with_error (
connection, connection,
MHD_HTTP_BAD_REQUEST, MHD_HTTP_BAD_REQUEST,
@ -180,7 +207,7 @@ TEH_handler_management_post_extensions (
if (json_array_size (extensions) != sec.num_extensions) if (json_array_size (extensions) != sec.num_extensions)
{ {
GNUNET_break_op (0); GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (top_spec);
return TALER_MHD_reply_with_error ( return TALER_MHD_reply_with_error (
connection, connection,
MHD_HTTP_BAD_REQUEST, MHD_HTTP_BAD_REQUEST,
@ -198,21 +225,21 @@ TEH_handler_management_post_extensions (
for (unsigned int i = 0; i<sec.num_extensions; i++) for (unsigned int i = 0; i<sec.num_extensions; i++)
{ {
// 1. parse the extension // 1. parse the extension out of the json
{
enum GNUNET_GenericReturnValue res; enum GNUNET_GenericReturnValue res;
const struct TALER_Extension *extension;
const char *name; const char *name;
struct GNUNET_JSON_Specification ispec[] = { struct GNUNET_JSON_Specification ext_spec[] = {
GNUNET_JSON_spec_string ("extension", GNUNET_JSON_spec_string ("extension",
&name), &name),
GNUNET_JSON_spec_json ("config", GNUNET_JSON_spec_json ("config",
&sec.extensions[i].config_json), &sec.extensions[i].config),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
}; };
res = TALER_MHD_parse_json_array (connection, res = TALER_MHD_parse_json_array (connection,
extensions, extensions,
ispec, ext_spec,
i, i,
-1); -1);
if (GNUNET_SYSERR == res) if (GNUNET_SYSERR == res)
@ -223,25 +250,13 @@ TEH_handler_management_post_extensions (
if (GNUNET_NO == res) if (GNUNET_NO == res)
{ {
ret = MHD_YES; ret = MHD_YES;
goto CLEANUP;; goto CLEANUP;
} }
/* Make sure name refers to a supported extension */ /* 2. Make sure name refers to a supported extension */
{ if (GNUNET_OK != TALER_get_extension_by_name (name,
bool found = false; TEH_extensions,
for (unsigned int k = 0; k < TALER_Extension_Max; k++) &extension))
{
if (0 == strncmp (name,
TEH_extensions[k].name,
strlen (TEH_extensions[k].name)))
{
sec.extensions[i].type = TEH_extensions[k].type;
found = true;
break;
}
}
if (! found)
{ {
ret = TALER_MHD_reply_with_error ( ret = TALER_MHD_reply_with_error (
connection, connection,
@ -250,53 +265,13 @@ TEH_handler_management_post_extensions (
"invalid extension type"); "invalid extension type");
goto CLEANUP; goto CLEANUP;
} }
}
/* We have a JSON object for the extension. sec.extensions[i].type = extension->type;
* Increment its refcount and free the parser.
* TODO: is this correct? */
json_incref (sec.extensions[i].config_json);
GNUNET_JSON_parse_free (ispec);
/* Make sure the config is sound */ /* 3. Extract the signature out of the json array */
{
switch (sec.extensions[i].type)
{
case TALER_Extension_AgeRestriction:
if (GNUNET_OK != TALER_agemask_parse_json (
sec.extensions[i].config_json,
&sec.extensions[i].mask))
{
ret = TALER_MHD_reply_with_error (
connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
"invalid mask for age restriction");
goto CLEANUP;
}
break;
case TALER_Extension_Peer2Peer:
/* TODO */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"peer2peer not yet supported in handler for /management/extensions\n");
ret = MHD_NO;
goto CLEANUP;
default:
/* not reachable */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"shouldn't be reached in handler for /management/extensions\n");
ret = MHD_NO;
goto CLEANUP;
}
}
}
// 2. parse and verify the signature
{ {
enum GNUNET_GenericReturnValue res; enum GNUNET_GenericReturnValue res;
struct GNUNET_JSON_Specification ispec[] = { struct GNUNET_JSON_Specification sig_spec[] = {
GNUNET_JSON_spec_fixed_auto (NULL, GNUNET_JSON_spec_fixed_auto (NULL,
&sec.extensions_sigs[i]), &sec.extensions_sigs[i]),
GNUNET_JSON_spec_end () GNUNET_JSON_spec_end ()
@ -304,7 +279,7 @@ TEH_handler_management_post_extensions (
res = TALER_MHD_parse_json_array (connection, res = TALER_MHD_parse_json_array (connection,
extensions_sigs, extensions_sigs,
ispec, sig_spec,
i, i,
-1); -1);
if (GNUNET_SYSERR == res) if (GNUNET_SYSERR == res)
@ -317,35 +292,13 @@ TEH_handler_management_post_extensions (
ret = MHD_YES; ret = MHD_YES;
goto CLEANUP; goto CLEANUP;
} }
/* verify the signature */
res = GNUNET_SYSERR;
switch (sec.extensions[i].type)
{
case TALER_Extension_AgeRestriction:
res = TALER_exchange_offline_extension_agemask_verify (
sec.extensions[i].mask,
&TEH_master_public_key,
&sec.extensions_sigs[i]);
break;
case TALER_Extension_Peer2Peer:
/* TODO */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Peer2peer not yet supported in handler for /management/extensions\n");
ret = MHD_NO;
goto CLEANUP;
default:
/* not reachable */
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"shouldn't be reached in handler for /management/extensions\n");
ret = MHD_NO;
goto CLEANUP;
} }
if (GNUNET_OK != res) /* 4. Verify the signature of the config */
if (GNUNET_OK != config_verify (
sec.extensions[i].config,
&TEH_master_public_key,
&sec.extensions_sigs[i]))
{ {
ret = TALER_MHD_reply_with_error ( ret = TALER_MHD_reply_with_error (
connection, connection,
@ -354,7 +307,26 @@ TEH_handler_management_post_extensions (
"invalid signature for extension"); "invalid signature for extension");
goto CLEANUP; goto CLEANUP;
} }
/* 5. Make sure the config is sound */
if (GNUNET_OK != extension->parse_config (NULL /* only verify */,
sec.extensions[i].config))
{
GNUNET_JSON_parse_free (ext_spec);
ret = TALER_MHD_reply_with_error (
connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_GENERIC_PARAMETER_MALFORMED,
"invalid configuration for extension");
goto CLEANUP;
} }
/* We have a validly signed JSON object for the extension.
* Increment its refcount and free the parser for the extension.
*/
json_incref (sec.extensions[i].config);
GNUNET_JSON_parse_free (ext_spec);
} /* for-loop */ } /* for-loop */
GNUNET_log (GNUNET_ERROR_TYPE_INFO, GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@ -386,14 +358,14 @@ TEH_handler_management_post_extensions (
CLEANUP: CLEANUP:
for (unsigned int i = 0; i < sec.num_extensions; i++) for (unsigned int i = 0; i < sec.num_extensions; i++)
{ {
if (NULL != sec.extensions[i].config_json) if (NULL != sec.extensions[i].config)
{ {
json_decref (sec.extensions[i].config_json); json_decref (sec.extensions[i].config);
} }
} }
GNUNET_free (sec.extensions); GNUNET_free (sec.extensions);
GNUNET_free (sec.extensions_sigs); GNUNET_free (sec.extensions_sigs);
GNUNET_JSON_parse_free (spec); GNUNET_JSON_parse_free (top_spec);
return ret; return ret;
} }

View File

@ -23,7 +23,6 @@
#define TALER_CRYPTO_LIB_H #define TALER_CRYPTO_LIB_H
#include <gnunet/gnunet_util_lib.h> #include <gnunet/gnunet_util_lib.h>
#include "taler_extensions.h"
#include "taler_error_codes.h" #include "taler_error_codes.h"
#include <gcrypt.h> #include <gcrypt.h>
@ -281,6 +280,26 @@ struct TALER_MasterSignatureP
struct GNUNET_CRYPTO_EddsaSignature eddsa_signature; struct GNUNET_CRYPTO_EddsaSignature eddsa_signature;
}; };
/*
* @brief Type of a list of age groups, represented as bit mask.
*
* The bits set in the mask mark the edges at the beginning of a next age
* group. F.e. for the age groups
* 0-7, 8-9, 10-11, 12-14, 14-15, 16-17, 18-21, 21-*
* the following bits are set:
*
* 31 24 16 8 0
* | | | | |
* oooooooo oo1oo1o1 o1o1o1o1 ooooooo1
*
* A value of 0 means that the exchange does not support the extension for
* age-restriction.
*/
struct TALER_AgeMask
{
uint32_t mask;
};
/** /**
* @brief Age restriction commitment of a coin. * @brief Age restriction commitment of a coin.
*/ */
@ -523,6 +542,19 @@ struct TALER_PickupIdentifierP
}; };
/**
* @brief Salted hash over the JSON object representing the configuration of an
* extension.
*/
struct TALER_ExtensionConfigHash
{
/**
* Actual hash value.
*/
struct GNUNET_HashCode hash;
};
GNUNET_NETWORK_STRUCT_END GNUNET_NETWORK_STRUCT_END
@ -2502,30 +2534,31 @@ TALER_merchant_wire_signature_make (
/* **************** /management/extensions offline signing **************** */ /* **************** /management/extensions offline signing **************** */
/** /**
* Create a signature for age restriction groups * Create a signature for the hash of the configuration of an extension
* *
* @param mask The bitmask representing age groups * @param h_config hash of the JSON object representing the configuration
* @param master_priv private key to sign with * @param master_priv private key to sign with
* @param[out] master_sig where to write the signature * @param[out] master_sig where to write the signature
*/ */
void void
TALER_exchange_offline_extension_agemask_sign ( TALER_exchange_offline_extension_config_hash_sign (
const struct TALER_AgeMask mask, const struct TALER_ExtensionConfigHash h_config,
const struct TALER_MasterPrivateKeyP *master_priv, const struct TALER_MasterPrivateKeyP *master_priv,
struct TALER_MasterSignatureP *master_sig); struct TALER_MasterSignatureP *master_sig);
/** /**
* Verify the signature in @a master_sig. * Verify the signature in @a master_sig of the given hash, taken over the JSON
* blob representing the configuration of an extension
* *
* @param mask bit mask representing an age group for age restriction * @param h_config hash of the JSON blob of a configuration of an extension
* @param master_pub master public key of the exchange * @param master_pub master public key of the exchange
* @param master_sig signature of the exchange * @param master_sig signature of the exchange
* @return #GNUNET_OK if signature is valid * @return #GNUNET_OK if signature is valid
*/ */
enum GNUNET_GenericReturnValue enum GNUNET_GenericReturnValue
TALER_exchange_offline_extension_agemask_verify ( TALER_exchange_offline_extension_config_hash_verify (
const struct TALER_AgeMask mask, const struct TALER_ExtensionConfigHash h_config,
const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_MasterSignatureP *master_sig const struct TALER_MasterSignatureP *master_sig
); );

View File

@ -23,6 +23,7 @@
#include <gnunet/gnunet_util_lib.h> #include <gnunet/gnunet_util_lib.h>
#include "taler_crypto_lib.h" #include "taler_crypto_lib.h"
#include "taler_json_lib.h"
#define TALER_EXTENSION_SECTION_PREFIX "exchange-extension-" #define TALER_EXTENSION_SECTION_PREFIX "exchange-extension-"
@ -39,41 +40,45 @@ enum TALER_Extension_Type
{ {
TALER_Extension_AgeRestriction = 0, TALER_Extension_AgeRestriction = 0,
TALER_Extension_Peer2Peer = 1, TALER_Extension_Peer2Peer = 1,
TALER_Extension_Max = 2 TALER_Extension_Max = 2 // Must be last
}; };
/*
* TODO oec: documentation
*/
struct TALER_Extension struct TALER_Extension
{ {
enum TALER_Extension_Type type; enum TALER_Extension_Type type;
char *name; char *name;
bool critical; bool critical;
void *config; void *config;
enum GNUNET_GenericReturnValue (*parse_config)(struct TALER_Extension *this,
const json_t *config);
json_t *(*config_to_json)(const struct TALER_Extension *this);
}; };
/**
* Generic functions for extensions
*/
/**
* Finds and returns a supported extension by a given name.
*
* @param name name of the extension to lookup
* @param extensions list of TALER_Extensions as haystack, terminated by an entry of type TALER_Extension_Max
* @param[out] ext set to the extension, if found, NULL otherwise
* @return GNUNET_OK if extension was found, GNUNET_NO otherwise
*/
enum GNUNET_GenericReturnValue
TALER_get_extension_by_name (const char *name,
const struct TALER_Extension *extensions,
const struct TALER_Extension **ext);
/* /*
* TALER Age Restriction Extension * TALER Age Restriction Extension
*/ */
/*
* @brief Type of a list of age groups, represented as bit mask.
*
* The bits set in the mask mark the edges at the beginning of a next age
* group. F.e. for the age groups
* 0-7, 8-9, 10-11, 12-14, 14-15, 16-17, 18-21, 21-*
* the following bits are set:
*
* 31 24 16 8 0
* | | | | |
* oooooooo oo1oo1o1 o1o1o1o1 ooooooo1
*
* A value of 0 means that the exchange does not support the extension for
* age-restriction.
*/
struct TALER_AgeMask
{
uint32_t mask;
};
#define TALER_EXTENSION_SECTION_AGE_RESTRICTION (TALER_EXTENSION_SECTION_PREFIX \ #define TALER_EXTENSION_SECTION_AGE_RESTRICTION (TALER_EXTENSION_SECTION_PREFIX \
"age_restriction") "age_restriction")
@ -86,7 +91,19 @@ struct TALER_AgeMask
<< 21) << 21)
/** /**
* @param groups String representation of age groups, like: "8:10:12:14:16:18:21" * @brief Parses a string as a list of age groups.
*
* The string must consist of a colon-separated list of increasing integers
* between 0 and 31. Each entry represents the beginning of a new age group.
* F.e. the string "8:10:12:14:16:18:21" parses into the following list of age
* groups
* 0-7, 8-9, 10-11, 12-13, 14-15, 16-17, 18-20, 21-...
* which then is represented as bit mask with the corresponding bits set:
* 31 24 16 8 0
* | | | | |
* oooooooo oo1oo1o1 o1o1o1o1 ooooooo1
*
* @param groups String representation of age groups
* @param[out] mask Mask representation for age restriction. * @param[out] mask Mask representation for age restriction.
* @return Error, if age groups were invalid, OK otherwise. * @return Error, if age groups were invalid, OK otherwise.
*/ */

View File

@ -532,7 +532,7 @@ TALER_JSON_wire_to_payto (const json_t *wire_s);
/** /**
* Hash @a extensions. * Hash @a extensions in deposits.
* *
* @param extensions contract extensions to hash * @param extensions contract extensions to hash
* @param[out] ech where to write the extension hash * @param[out] ech where to write the extension hash
@ -541,6 +541,16 @@ void
TALER_deposit_extension_hash (const json_t *extensions, TALER_deposit_extension_hash (const json_t *extensions,
struct TALER_ExtensionContractHash *ech); struct TALER_ExtensionContractHash *ech);
/**
* Hash the @a config of an extension, given as JSON
*
* @param config configuration of the extension
* @param[out] eh where to write the extension hash
* @return GNUNET_OK on success, GNUNET_SYSERR on failure
*/
enum GNUNET_GenericReturnValue
TALER_extension_config_hash (const json_t *config,
struct TALER_ExtensionConfigHash *eh);
/** /**
* Parses a JSON object { "extension": "age_restriction", "mask": <uint32> }. * Parses a JSON object { "extension": "age_restriction", "mask": <uint32> }.
@ -553,7 +563,6 @@ enum GNUNET_GenericReturnValue
TALER_agemask_parse_json (const json_t *root, TALER_agemask_parse_json (const json_t *root,
struct TALER_AgeMask *mask); struct TALER_AgeMask *mask);
#endif /* TALER_JSON_LIB_H_ */ #endif /* TALER_JSON_LIB_H_ */
/* End of taler_json_lib.h */ /* End of taler_json_lib.h */

View File

@ -967,9 +967,9 @@ struct TALER_MasterDelWirePS
/* /*
* @brief Signature made by the exchange offline key over the * @brief Signature made by the exchange offline key over the
* configuration of the age restriction extension. * configuration of an extension.
*/ */
struct TALER_MasterExtensionAgeRestrictionPS struct TALER_MasterExtensionConfigurationPS
{ {
/** /**
* Purpose is #TALER_SIGNATURE_MASTER_EXTENSION. Signed * Purpose is #TALER_SIGNATURE_MASTER_EXTENSION. Signed
@ -978,29 +978,11 @@ struct TALER_MasterExtensionAgeRestrictionPS
struct GNUNET_CRYPTO_EccSignaturePurpose purpose; struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
/** /**
* Bit mask representing the lits of age groups, see TALER_AgeMask for a * Hash of the JSON object that represents the configuration of an extension.
* description.
*/ */
struct TALER_AgeMask mask; struct TALER_ExtensionConfigHash h_config GNUNET_PACKED;
}; };
#if 0
/*
* @brief Signature made by the exchange offline key over the
* configuration of the peer2peer extension.
*/
struct TALER_MasterExtensionPeer2PeerPS
{
/**
* Purpose is #TALER_SIGNATURE_MASTER_EXTENSION. Signed
* by a `struct TALER_MasterPublicKeyP` using EdDSA.
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
// TODO oec
};
#endif
/** /**
* @brief Information about a denomination key. Denomination keys * @brief Information about a denomination key. Denomination keys
* are used to sign coins of a certain value into existence. * are used to sign coins of a certain value into existence.

View File

@ -1009,4 +1009,14 @@ TALER_deposit_extension_hash (const json_t *extensions,
} }
enum GNUNET_GenericReturnValue
TALER_extension_config_hash (const json_t *config,
struct TALER_ExtensionConfigHash *ech)
{
return dump_and_hash (config,
"taler-extension-configuration",
&ech->hash);
}
/* End of json/json.c */ /* End of json/json.c */

View File

@ -153,32 +153,17 @@ TALER_EXCHANGE_management_post_extensions (
GNUNET_assert (NULL != extensions); GNUNET_assert (NULL != extensions);
for (unsigned int i = 0; i<pkd->num_extensions; i++) for (unsigned int i = 0; i<pkd->num_extensions; i++)
{ {
json_t *config; const json_t *config;
const struct TALER_AgeMask *mask;
const struct TALER_Extension *ext = &pkd->extensions[i]; const struct TALER_Extension *ext = &pkd->extensions[i];
switch (ext->type) config = ext->config_to_json (ext);
{
// TODO: case TALER_Extension_Peer2Peer
case TALER_Extension_AgeRestriction:
mask = (const struct TALER_AgeMask *) (&ext->config);
config = GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("extension",
ext->name),
GNUNET_JSON_pack_data_auto ("mask",
&mask->mask));
GNUNET_assert (NULL != config);
break;
default:
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Extension not supported.\n");
}
GNUNET_assert (NULL != config);
GNUNET_assert (0 == GNUNET_assert (0 ==
json_array_append_new ( json_array_append_new (
extensions, extensions,
GNUNET_JSON_PACK ( GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto ("name", GNUNET_JSON_pack_data_auto ("extension",
&ext->name), &ext->name),
GNUNET_JSON_pack_data_auto ("config", GNUNET_JSON_pack_data_auto ("config",
config) config)

View File

@ -72,6 +72,7 @@ libtalerutil_la_SOURCES = \
crypto_wire.c \ crypto_wire.c \
denom.c \ denom.c \
exchange_signatures.c \ exchange_signatures.c \
extensions.c \
extension_age_restriction.c \ extension_age_restriction.c \
getopt.c \ getopt.c \
lang.c \ lang.c \

49
src/util/extensions.c Normal file
View File

@ -0,0 +1,49 @@
/*
This file is part of TALER
Copyright (C) 2014-2021 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file extensions.c
* @brief Utility functions for extensions
* @author Özgür Kesim
*/
#include "platform.h"
#include "taler_util.h"
#include "taler_extensions.h"
#include "stdint.h"
enum GNUNET_GenericReturnValue
TALER_get_extension_by_name (const char *name,
const struct TALER_Extension *extensions,
const struct TALER_Extension **ext)
{
const struct TALER_Extension *it = extensions;
for (; it->type != TALER_Extension_Max; it++)
{
if (0 == strncmp (name,
it->name,
strlen (it->name)))
{
*ext = it;
return GNUNET_OK;
}
}
return GNUNET_NO;
}
/* end of extensions.c */

View File

@ -491,66 +491,40 @@ TALER_exchange_offline_wire_fee_verify (
void void
TALER_exchange_offline_extension_agemask_sign ( TALER_exchange_offline_extension_config_hash_sign (
const struct TALER_AgeMask mask, const struct TALER_ExtensionConfigHash h_config,
const struct TALER_MasterPrivateKeyP *master_priv, const struct TALER_MasterPrivateKeyP *master_priv,
struct TALER_MasterSignatureP *master_sig) struct TALER_MasterSignatureP *master_sig)
{ {
struct TALER_MasterExtensionAgeRestrictionPS ar = { struct TALER_MasterExtensionConfigurationPS ec = {
.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_EXTENSION), .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_EXTENSION),
.purpose.size = htonl (sizeof(ar)), .purpose.size = htonl (sizeof(ec)),
.mask = mask .h_config = h_config
}; };
GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv,
&ar, &ec,
&master_sig->eddsa_signature); &master_sig->eddsa_signature);
} }
enum GNUNET_GenericReturnValue enum GNUNET_GenericReturnValue
TALER_exchange_offline_extension_agemask_verify ( TALER_exchange_offline_extension_config_hash_verify (
const struct TALER_AgeMask mask, const struct TALER_ExtensionConfigHash h_config,
const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_MasterSignatureP *master_sig const struct TALER_MasterSignatureP *master_sig
) )
{ {
struct TALER_MasterExtensionAgeRestrictionPS ar = { struct TALER_MasterExtensionConfigurationPS ec = {
.purpose.purpose = htonl (TALER_SIGNATURE_MASTER_EXTENSION), .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_EXTENSION),
.purpose.size = htonl (sizeof(ar)), .purpose.size = htonl (sizeof(ec)),
.mask = mask .h_config = h_config
}; };
return
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_EXTENSION, return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_EXTENSION,
&ar, &ec,
&master_sig->eddsa_signature, &master_sig->eddsa_signature,
&master_pub->eddsa_pub); &master_pub->eddsa_pub);
} }
#if 0
/* TODO peer2peer */
void
TALER_exchange_offline_extension_p2p_sign (
// TODO
const struct TALER_MasterPrivateKeyP *master_priv,
struct TALER_MasterSignatureP *master_sig)
{
// TODO
}
enum GNUNET_GenericReturnValue
TALER_exchange_offline_extension_p2p_verify (
// TODO
const struct TALER_MasterPublicKeyP *master_pub,
const struct TALER_MasterSignatureP *master_sig,
)
{
// TODO
return GNUNET_FALSE;
}
#endif
/* end of offline_signatures.c */ /* end of offline_signatures.c */