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:
parent
128d136885
commit
75763f2823
@ -1,18 +1,18 @@
|
|||||||
/*
|
/*
|
||||||
This file is part of TALER
|
This file is part of TALER
|
||||||
Copyright (C) 2014-2021 Taler Systems SA
|
Copyright (C) 2014-2021 Taler Systems SA
|
||||||
|
|
||||||
TALER is free software; you can redistribute it and/or modify it under the
|
TALER is free software; you can redistribute it and/or modify it under the
|
||||||
terms of the GNU Affero 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.
|
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
|
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
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
||||||
A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
|
A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License along with
|
You should have received a copy of the GNU Affero General Public License along with
|
||||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* @file taler-exchange-httpd.c
|
* @file taler-exchange-httpd.c
|
||||||
* @brief Serve the HTTP interface of the exchange
|
* @brief Serve the HTTP interface of the exchange
|
||||||
@ -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,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -485,7 +499,7 @@ proceed_with_handler (struct TEH_RequestContext *rc,
|
|||||||
if (GNUNET_SYSERR == res)
|
if (GNUNET_SYSERR == res)
|
||||||
{
|
{
|
||||||
GNUNET_assert (NULL == root);
|
GNUNET_assert (NULL == root);
|
||||||
return MHD_NO; /* bad upload, could not even generate error */
|
return MHD_NO; /* bad upload, could not even generate error */
|
||||||
}
|
}
|
||||||
if ( (GNUNET_NO == res) ||
|
if ( (GNUNET_NO == res) ||
|
||||||
(NULL == root) )
|
(NULL == root) )
|
||||||
@ -528,8 +542,8 @@ proceed_with_handler (struct TEH_RequestContext *rc,
|
|||||||
sizeof (emsg),
|
sizeof (emsg),
|
||||||
"Got %u/%u segments for %s request ('%s')",
|
"Got %u/%u segments for %s request ('%s')",
|
||||||
(NULL == args[i - 1])
|
(NULL == args[i - 1])
|
||||||
? i - 1
|
? i - 1
|
||||||
: i + ((NULL != fin) ? 1 : 0),
|
: i + ((NULL != fin) ? 1 : 0),
|
||||||
rh->nargs,
|
rh->nargs,
|
||||||
rh->url,
|
rh->url,
|
||||||
url);
|
url);
|
||||||
@ -553,7 +567,7 @@ proceed_with_handler (struct TEH_RequestContext *rc,
|
|||||||
root,
|
root,
|
||||||
args);
|
args);
|
||||||
else /* We also only have "POST" or "GET" in the API for at this point
|
else /* We also only have "POST" or "GET" in the API for at this point
|
||||||
(OPTIONS/HEAD are taken care of earlier) */
|
(OPTIONS/HEAD are taken care of earlier) */
|
||||||
ret = rh->handler.get (rc,
|
ret = rh->handler.get (rc,
|
||||||
args);
|
args);
|
||||||
}
|
}
|
||||||
@ -1120,7 +1134,7 @@ handle_mhd_request (void *cls,
|
|||||||
|
|
||||||
if (0 == strcasecmp (method,
|
if (0 == strcasecmp (method,
|
||||||
MHD_HTTP_METHOD_HEAD))
|
MHD_HTTP_METHOD_HEAD))
|
||||||
method = MHD_HTTP_METHOD_GET; /* treat HEAD as GET here, MHD will do the rest */
|
method = MHD_HTTP_METHOD_GET; /* treat HEAD as GET here, MHD will do the rest */
|
||||||
|
|
||||||
/* parse first part of URL */
|
/* parse first part of URL */
|
||||||
{
|
{
|
||||||
@ -1954,8 +1968,8 @@ run (void *cls,
|
|||||||
MHD_OPTION_CONNECTION_TIMEOUT,
|
MHD_OPTION_CONNECTION_TIMEOUT,
|
||||||
connection_timeout,
|
connection_timeout,
|
||||||
(0 == allow_address_reuse)
|
(0 == allow_address_reuse)
|
||||||
? MHD_OPTION_END
|
? MHD_OPTION_END
|
||||||
: MHD_OPTION_LISTENING_ADDRESS_REUSE,
|
: MHD_OPTION_LISTENING_ADDRESS_REUSE,
|
||||||
(unsigned int) allow_address_reuse,
|
(unsigned int) allow_address_reuse,
|
||||||
MHD_OPTION_END);
|
MHD_OPTION_END);
|
||||||
if (NULL == mhd)
|
if (NULL == mhd)
|
||||||
|
@ -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.
|
||||||
|
@ -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,105 +225,53 @@ 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;
|
||||||
|
const struct TALER_Extension *extension;
|
||||||
|
const char *name;
|
||||||
|
struct GNUNET_JSON_Specification ext_spec[] = {
|
||||||
|
GNUNET_JSON_spec_string ("extension",
|
||||||
|
&name),
|
||||||
|
GNUNET_JSON_spec_json ("config",
|
||||||
|
&sec.extensions[i].config),
|
||||||
|
GNUNET_JSON_spec_end ()
|
||||||
|
};
|
||||||
|
|
||||||
|
res = TALER_MHD_parse_json_array (connection,
|
||||||
|
extensions,
|
||||||
|
ext_spec,
|
||||||
|
i,
|
||||||
|
-1);
|
||||||
|
if (GNUNET_SYSERR == res)
|
||||||
{
|
{
|
||||||
enum GNUNET_GenericReturnValue res;
|
ret = MHD_NO; /* hard failure */
|
||||||
const char *name;
|
goto CLEANUP;
|
||||||
struct GNUNET_JSON_Specification ispec[] = {
|
}
|
||||||
GNUNET_JSON_spec_string ("extension",
|
if (GNUNET_NO == res)
|
||||||
&name),
|
{
|
||||||
GNUNET_JSON_spec_json ("config",
|
ret = MHD_YES;
|
||||||
&sec.extensions[i].config_json),
|
goto CLEANUP;
|
||||||
GNUNET_JSON_spec_end ()
|
|
||||||
};
|
|
||||||
|
|
||||||
res = TALER_MHD_parse_json_array (connection,
|
|
||||||
extensions,
|
|
||||||
ispec,
|
|
||||||
i,
|
|
||||||
-1);
|
|
||||||
if (GNUNET_SYSERR == res)
|
|
||||||
{
|
|
||||||
ret = MHD_NO; /* hard failure */
|
|
||||||
goto CLEANUP;
|
|
||||||
}
|
|
||||||
if (GNUNET_NO == res)
|
|
||||||
{
|
|
||||||
ret = MHD_YES;
|
|
||||||
goto CLEANUP;;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure name refers to a supported extension */
|
|
||||||
{
|
|
||||||
bool found = false;
|
|
||||||
for (unsigned int k = 0; k < TALER_Extension_Max; k++)
|
|
||||||
{
|
|
||||||
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 (
|
|
||||||
connection,
|
|
||||||
MHD_HTTP_BAD_REQUEST,
|
|
||||||
TALER_EC_GENERIC_PARAMETER_MALFORMED,
|
|
||||||
"invalid extension type");
|
|
||||||
goto CLEANUP;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We have a JSON object for the extension.
|
|
||||||
* 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 */
|
|
||||||
{
|
|
||||||
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
|
/* 2. Make sure name refers to a supported extension */
|
||||||
|
if (GNUNET_OK != TALER_get_extension_by_name (name,
|
||||||
|
TEH_extensions,
|
||||||
|
&extension))
|
||||||
|
{
|
||||||
|
ret = TALER_MHD_reply_with_error (
|
||||||
|
connection,
|
||||||
|
MHD_HTTP_BAD_REQUEST,
|
||||||
|
TALER_EC_GENERIC_PARAMETER_MALFORMED,
|
||||||
|
"invalid extension type");
|
||||||
|
goto CLEANUP;
|
||||||
|
}
|
||||||
|
|
||||||
|
sec.extensions[i].type = extension->type;
|
||||||
|
|
||||||
|
/* 3. Extract the signature out of the json array */
|
||||||
{
|
{
|
||||||
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,44 +292,41 @@ 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)
|
|
||||||
{
|
|
||||||
ret = TALER_MHD_reply_with_error (
|
|
||||||
connection,
|
|
||||||
MHD_HTTP_BAD_REQUEST,
|
|
||||||
TALER_EC_GENERIC_PARAMETER_MALFORMED,
|
|
||||||
"invalid signature for extension");
|
|
||||||
goto CLEANUP;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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 (
|
||||||
|
connection,
|
||||||
|
MHD_HTTP_BAD_REQUEST,
|
||||||
|
TALER_EC_GENERIC_PARAMETER_MALFORMED,
|
||||||
|
"invalid signature for extension");
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
);
|
);
|
||||||
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
@ -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 */
|
||||||
|
@ -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.
|
||||||
|
@ -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 */
|
||||||
|
@ -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)
|
||||||
|
@ -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
49
src/util/extensions.c
Normal 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 */
|
@ -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 */
|
||||||
|
Loading…
Reference in New Issue
Block a user