diff options
Diffstat (limited to 'src/util')
41 files changed, 3262 insertions, 1214 deletions
diff --git a/src/util/.gitignore b/src/util/.gitignore index c5f8c76dd..d79786ec7 100644 --- a/src/util/.gitignore +++ b/src/util/.gitignore @@ -9,3 +9,4 @@ test_helper_cs test_helper_cs_home/ test_helper_eddsa test_helper_eddsa_home/ +test_conversion diff --git a/src/util/Makefile.am b/src/util/Makefile.am index 115ea5055..d2504588b 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am @@ -10,6 +10,7 @@ endif pkgcfgdir = $(prefix)/share/taler/config.d/ pkgcfg_DATA = \ + currencies.conf \ paths.conf \ taler-exchange-secmod-eddsa.conf \ taler-exchange-secmod-rsa.conf \ @@ -20,7 +21,8 @@ EXTRA_DIST = \ taler-config.in \ test_helper_eddsa.conf \ test_helper_rsa.conf \ - test_helper_cs.conf + test_helper_cs.conf \ + test_conversion.sh bin_PROGRAMS = \ taler-exchange-secmod-eddsa \ @@ -80,6 +82,7 @@ libtalerutil_la_SOURCES = \ aml_signatures.c \ auditor_signatures.c \ config.c \ + conversion.c \ crypto.c \ crypto_confirmation.c \ crypto_contract.c \ @@ -112,11 +115,12 @@ libtalerutil_la_LIBADD = \ -ljansson \ $(LIBGCRYPT_LIBS) \ -lmicrohttpd $(XLIB) \ + -lunistring \ -lz \ -lm libtalerutil_la_LDFLAGS = \ - -version-info 0:0:0 \ + -version-info 3:3:2 \ -no-undefined @@ -125,6 +129,7 @@ AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH= check_PROGRAMS = \ test_age_restriction \ test_amount \ + test_conversion \ test_crypto \ test_helper_eddsa \ test_helper_rsa \ @@ -141,6 +146,14 @@ test_age_restriction_LDADD = \ -lgnunetutil \ libtalerutil.la +test_conversion_SOURCES = \ + test_conversion.c +test_conversion_LDADD = \ + -lgnunetjson \ + -lgnunetutil \ + -ljansson \ + libtalerutil.la + test_amount_SOURCES = \ test_amount.c test_amount_LDADD = \ diff --git a/src/util/age_restriction.c b/src/util/age_restriction.c index beb68e5a6..c2a7fc07c 100644 --- a/src/util/age_restriction.c +++ b/src/util/age_restriction.c @@ -23,6 +23,7 @@ #include "taler_signatures.h" #include <gnunet/gnunet_json_lib.h> #include <gcrypt.h> +#include <stdint.h> struct #ifndef AGE_RESTRICTION_WITH_ECDSA @@ -31,10 +32,10 @@ GNUNET_CRYPTO_Edx25519PublicKey GNUNET_CRYPTO_EcdsaPublicKey #endif TALER_age_commitment_base_public_key = { - .q_y = { 0x6f, 0xe5, 0x87, 0x9a, 0x3d, 0xa9, 0x44, 0x20, - 0x80, 0xbd, 0x6a, 0xb9, 0x44, 0x56, 0x91, 0x19, - 0xaf, 0xb4, 0xc8, 0x7b, 0x89, 0xce, 0x23, 0x17, - 0x97, 0x20, 0x5c, 0xbb, 0x9c, 0xd7, 0xcc, 0xd9}, + .q_y = { 0x64, 0x41, 0xb9, 0xbd, 0xbf, 0x14, 0x39, 0x8e, + 0x46, 0xeb, 0x5c, 0x1d, 0x34, 0xd3, 0x9b, 0x2f, + 0x9b, 0x7d, 0xc8, 0x18, 0xeb, 0x9c, 0x09, 0xfb, + 0x43, 0xad, 0x16, 0x64, 0xbc, 0x18, 0x49, 0xb5}, }; void @@ -76,7 +77,7 @@ TALER_age_commitment_hash ( * defined by the given mask. */ uint8_t -get_age_group ( +TALER_get_age_group ( const struct TALER_AgeMask *mask, uint8_t age) { @@ -95,47 +96,66 @@ get_age_group ( } +uint8_t +TALER_get_lowest_age ( + const struct TALER_AgeMask *mask, + uint8_t age) +{ + uint32_t m = mask->bits; + uint8_t group = TALER_get_age_group (mask, age); + uint8_t lowest = 0; + + while (group > 0) + { + m = m >> 1; + if (m & 1) + group--; + lowest++; + } + + return lowest; +} + + #ifdef AGE_RESTRICTION_WITH_ECDSA -/* @brief Helper function to generate a ECDSA private key +/** + * @brief Helper function to generate a ECDSA private key * * @param seed Input seed * @param size Size of the seed in bytes * @param[out] pkey ECDSA private key - * @return GNUNET_OK on success */ -static enum GNUNET_GenericReturnValue +static void ecdsa_create_from_seed ( const void *seed, size_t seed_size, struct GNUNET_CRYPTO_EcdsaPrivateKey *key) { enum GNUNET_GenericReturnValue ret; - ret = GNUNET_CRYPTO_kdf (key, - sizeof (*key), - &seed, - seed_size, - "age commitment", - sizeof ("age commitment") - 1, - NULL, 0); - if (GNUNET_OK != ret) - return ret; + GNUNET_assert ( + GNUNET_OK == + GNUNET_CRYPTO_kdf (key, + sizeof (*key), + &seed, + seed_size, + "age commitment", + sizeof ("age commitment") - 1, + NULL, 0)); /* See GNUNET_CRYPTO_ecdsa_key_create */ key->d[0] &= 248; key->d[31] &= 127; key->d[31] |= 64; - - return GNUNET_OK; } #endif -enum GNUNET_GenericReturnValue +void TALER_age_restriction_commit ( const struct TALER_AgeMask *mask, - const uint8_t age, + uint8_t age, const struct GNUNET_HashCode *seed, struct TALER_AgeCommitmentProof *ncp) { @@ -147,10 +167,10 @@ TALER_age_restriction_commit ( GNUNET_assert (NULL != mask); GNUNET_assert (NULL != seed); GNUNET_assert (NULL != ncp); - GNUNET_assert (mask->bits & 1); /* fist bit must have been set */ + GNUNET_assert (mask->bits & 1); /* first bit must have been set */ num_pub = __builtin_popcount (mask->bits) - 1; - num_priv = get_age_group (mask, age); + num_priv = TALER_get_age_group (mask, age); GNUNET_assert (31 > num_priv); GNUNET_assert (num_priv <= num_pub); @@ -190,24 +210,15 @@ TALER_age_restriction_commit ( GNUNET_CRYPTO_edx25519_key_get_public (&pkey->priv, &ncp->commitment.keys[i].pub); #else - if (GNUNET_OK != - ecdsa_create_from_seed (&seed_i, - sizeof(seed_i), - &pkey->priv)) - { - GNUNET_free (ncp->commitment.keys); - GNUNET_free (ncp->proof.keys); - return GNUNET_SYSERR; - } - + ecdsa_create_from_seed (&seed_i, + sizeof(seed_i), + &pkey->priv); GNUNET_CRYPTO_ecdsa_key_get_public (&pkey->priv, &ncp->commitment.keys[i].pub); #endif seed_i.bits[0] += 1; } - - return GNUNET_OK; } @@ -335,8 +346,8 @@ TALER_age_commitment_attest ( GNUNET_assert (NULL != attest); GNUNET_assert (NULL != cp); - group = get_age_group (&cp->commitment.mask, - age); + group = TALER_get_age_group (&cp->commitment.mask, + age); GNUNET_assert (group < 32); @@ -370,6 +381,7 @@ TALER_age_commitment_attest ( &at, &attest->signature); } +#undef sign return GNUNET_OK; } @@ -386,8 +398,8 @@ TALER_age_commitment_verify ( GNUNET_assert (NULL != attest); GNUNET_assert (NULL != comm); - group = get_age_group (&comm->mask, - age); + group = TALER_get_age_group (&comm->mask, + age); GNUNET_assert (group < 32); @@ -419,6 +431,7 @@ TALER_age_commitment_verify ( &attest->signature, &comm->keys[group - 1].pub); } +#undef verify } @@ -442,6 +455,9 @@ void TALER_age_proof_free ( struct TALER_AgeProof *proof) { + if (NULL == proof) + return; + if (NULL != proof->keys) { GNUNET_CRYPTO_zero_keys ( @@ -457,26 +473,71 @@ TALER_age_proof_free ( void TALER_age_commitment_proof_free ( - struct TALER_AgeCommitmentProof *cp) + struct TALER_AgeCommitmentProof *acp) { - if (NULL != cp->proof.keys) + if (NULL == acp) + return; + + if (NULL != acp->proof.keys) { GNUNET_CRYPTO_zero_keys ( - cp->proof.keys, - sizeof(*cp->proof.keys) * cp->proof.num); + acp->proof.keys, + sizeof(*acp->proof.keys) * acp->proof.num); - GNUNET_free (cp->proof.keys); - cp->proof.keys = NULL; + GNUNET_free (acp->proof.keys); + acp->proof.keys = NULL; } - if (NULL != cp->commitment.keys) + if (NULL != acp->commitment.keys) { - GNUNET_free (cp->commitment.keys); - cp->commitment.keys = NULL; + GNUNET_free (acp->commitment.keys); + acp->commitment.keys = NULL; } } +struct TALER_AgeCommitmentProof * +TALER_age_commitment_proof_duplicate ( + const struct TALER_AgeCommitmentProof *acp) +{ + struct TALER_AgeCommitmentProof *nacp; + + GNUNET_assert (NULL != acp); + GNUNET_assert (__builtin_popcount (acp->commitment.mask.bits) - 1 == + (int) acp->commitment.num); + + nacp = GNUNET_new (struct TALER_AgeCommitmentProof); + + TALER_age_commitment_proof_deep_copy (acp,nacp); + return nacp; +} + + +void +TALER_age_commitment_proof_deep_copy ( + const struct TALER_AgeCommitmentProof *acp, + struct TALER_AgeCommitmentProof *nacp) +{ + GNUNET_assert (NULL != acp); + GNUNET_assert (__builtin_popcount (acp->commitment.mask.bits) - 1 == + (int) acp->commitment.num); + + *nacp = *acp; + nacp->commitment.keys = + GNUNET_new_array (acp->commitment.num, + struct TALER_AgeCommitmentPublicKeyP); + nacp->proof.keys = + GNUNET_new_array (acp->proof.num, + struct TALER_AgeCommitmentPrivateKeyP); + + for (size_t i = 0; i < acp->commitment.num; i++) + nacp->commitment.keys[i] = acp->commitment.keys[i]; + + for (size_t i = 0; i < acp->proof.num; i++) + nacp->proof.keys[i] = acp->proof.keys[i]; +} + + enum GNUNET_GenericReturnValue TALER_JSON_parse_age_groups (const json_t *root, struct TALER_AgeMask *mask) @@ -513,6 +574,9 @@ TALER_parse_age_group_string ( unsigned int val = 0; char c; + /* reset mask */ + mask->bits = 0; + while (*pos) { c = *pos++; @@ -546,19 +610,16 @@ TALER_parse_age_group_string ( } -char * +const char * TALER_age_mask_to_string ( const struct TALER_AgeMask *mask) { + static char buf[256] = {0}; uint32_t bits = mask->bits; unsigned int n = 0; - char *buf = GNUNET_malloc (32 * 3); // max characters possible char *pos = buf; - if (NULL == buf) - { - return buf; - } + memset (buf, 0, sizeof(buf)); while (bits != 0) { @@ -584,7 +645,7 @@ TALER_age_mask_to_string ( } -enum GNUNET_GenericReturnValue +void TALER_age_restriction_from_secret ( const struct TALER_PlanchetMasterSecretP *secret, const struct TALER_AgeMask *mask, @@ -601,7 +662,7 @@ TALER_age_restriction_from_secret ( GNUNET_assert (mask->bits & 1); /* fist bit must have been set */ num_pub = __builtin_popcount (mask->bits) - 1; - num_priv = get_age_group (mask, max_age); + num_priv = TALER_get_age_group (mask, max_age); GNUNET_assert (31 > num_priv); GNUNET_assert (num_priv <= num_pub); @@ -610,11 +671,9 @@ TALER_age_restriction_from_secret ( ncp->commitment.num = num_pub; ncp->proof.num = num_priv; ncp->proof.keys = NULL; - ncp->commitment.keys = GNUNET_new_array ( num_pub, struct TALER_AgeCommitmentPublicKeyP); - if (0 < num_priv) ncp->proof.keys = GNUNET_new_array ( num_priv, @@ -622,7 +681,7 @@ TALER_age_restriction_from_secret ( /* Create as many private keys as allow with max_age and derive the * corresponding public keys. The rest of the needed public keys are created - * by scalar mulitplication with the TALER_age_commitment_base_public_key. */ + * by scalar multiplication with the TALER_age_commitment_base_public_key. */ for (size_t i = 0; i < num_pub; i++) { enum GNUNET_GenericReturnValue ret; @@ -648,14 +707,9 @@ TALER_age_restriction_from_secret ( GNUNET_CRYPTO_edx25519_key_get_public (&pkey->priv, &ncp->commitment.keys[i].pub); #else - if (GNUNET_OK != ecdsa_create_from_seed (&seed_i, - sizeof(seed_i), - &pkey->priv)) - { - GNUNET_free (ncp->commitment.keys); - GNUNET_free (ncp->proof.keys); - return GNUNET_SYSERR; - } + ecdsa_create_from_seed (&seed_i, + sizeof(seed_i), + &pkey->priv); GNUNET_CRYPTO_ecdsa_key_get_public (&pkey->priv, &ncp->commitment.keys[i].pub); #endif @@ -680,9 +734,61 @@ TALER_age_restriction_from_secret ( #endif } } +} - return GNUNET_OK; +enum GNUNET_GenericReturnValue +TALER_parse_coarse_date ( + const char *in, + const struct TALER_AgeMask *mask, + uint32_t *out) +{ + struct tm date = {0}; + struct tm limit = {0}; + time_t seconds; + + if (NULL == in) + { + /* FIXME[oec]: correct behaviour? */ + *out = 0; + return GNUNET_OK; + } + + GNUNET_assert (NULL !=mask); + GNUNET_assert (NULL !=out); + + if (NULL == strptime (in, "%Y-%m-%d", &date)) + { + if (NULL == strptime (in, "%Y-%m-00", &date)) + if (NULL == strptime (in, "%Y-00-00", &date)) + return GNUNET_SYSERR; + /* turns out that the day is off by one in the last two cases */ + date.tm_mday += 1; + } + + seconds = timegm (&date); + if (-1 == seconds) + return GNUNET_SYSERR; + + /* calculate the limit date for the largest age group */ + { + time_t l = time (NULL); + localtime_r (&l, &limit); + } + limit.tm_year -= TALER_adult_age (mask); + GNUNET_assert (-1 != timegm (&limit)); + + if ((limit.tm_year < date.tm_year) + || ((limit.tm_year == date.tm_year) + && (limit.tm_mon < date.tm_mon)) + || ((limit.tm_year == date.tm_year) + && (limit.tm_mon == date.tm_mon) + && (limit.tm_mday < date.tm_mday))) + *out = seconds / 60 / 60 / 24; + else + *out = 0; + + return GNUNET_OK; } diff --git a/src/util/aml_signatures.c b/src/util/aml_signatures.c index 6d90b25c2..a61646c0d 100644 --- a/src/util/aml_signatures.c +++ b/src/util/aml_signatures.c @@ -85,6 +85,7 @@ TALER_officer_aml_decision_sign ( struct TALER_AmlDecisionPS ad = { .purpose.purpose = htonl (TALER_SIGNATURE_AML_DECISION), .purpose.size = htonl (sizeof (ad)), + .decision_time = GNUNET_TIME_timestamp_hton (decision_time), .h_payto = *h_payto, .new_state = htonl ((uint32_t) new_state) }; @@ -117,6 +118,7 @@ TALER_officer_aml_decision_verify ( struct TALER_AmlDecisionPS ad = { .purpose.purpose = htonl (TALER_SIGNATURE_AML_DECISION), .purpose.size = htonl (sizeof (ad)), + .decision_time = GNUNET_TIME_timestamp_hton (decision_time), .h_payto = *h_payto, .new_state = htonl ((uint32_t) new_state) }; diff --git a/src/util/amount.c b/src/util/amount.c index d5698e8b6..cce84d73a 100644 --- a/src/util/amount.c +++ b/src/util/amount.c @@ -40,6 +40,31 @@ invalidate (struct TALER_Amount *a) enum GNUNET_GenericReturnValue +TALER_check_currency (const char *str) +{ + if (strlen (str) >= TALER_CURRENCY_LEN) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Currency code name `%s' is too long\n", + str); + return GNUNET_SYSERR; + } + /* validate str has only legal characters in it! */ + for (unsigned int i = 0; '\0' != str[i]; i++) + { + if ( ('A' > str[i]) || ('Z' < str[i]) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Currency code name `%s' contains illegal characters (only A-Z allowed)\n", + str); + return GNUNET_SYSERR; + } + } + return GNUNET_OK; +} + + +enum GNUNET_GenericReturnValue TALER_string_to_amount (const char *str, struct TALER_Amount *amount) { @@ -62,6 +87,7 @@ TALER_string_to_amount (const char *str, /* parse currency */ colon = strchr (str, (int) ':'); if ( (NULL == colon) || + (colon == str) || ((colon - str) >= TALER_CURRENCY_LEN) ) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, @@ -72,14 +98,15 @@ TALER_string_to_amount (const char *str, } GNUNET_assert (TALER_CURRENCY_LEN > (colon - str)); - memcpy (amount->currency, - str, - colon - str); + for (unsigned int i = 0; i<colon - str; i++) + amount->currency[i] = str[i]; /* 0-terminate *and* normalize buffer by setting everything to '\0' */ memset (&amount->currency [colon - str], 0, TALER_CURRENCY_LEN - (colon - str)); - + if (GNUNET_OK != + TALER_check_currency (amount->currency)) + return GNUNET_SYSERR; /* skip colon */ value = colon + 1; if ('\0' == value[0]) @@ -193,9 +220,8 @@ TALER_amount_hton (struct TALER_AmountNBO *res, TALER_amount_is_valid (d)); res->value = GNUNET_htonll (d->value); res->fraction = htonl (d->fraction); - memcpy (res->currency, - d->currency, - TALER_CURRENCY_LEN); + for (unsigned int i = 0; i<TALER_CURRENCY_LEN; i++) + res->currency[i] = d->currency[i]; } @@ -205,9 +231,9 @@ TALER_amount_ntoh (struct TALER_Amount *res, { res->value = GNUNET_ntohll (dn->value); res->fraction = ntohl (dn->fraction); - memcpy (res->currency, - dn->currency, - TALER_CURRENCY_LEN); + GNUNET_memcpy (res->currency, + dn->currency, + TALER_CURRENCY_LEN); GNUNET_assert (GNUNET_YES == TALER_amount_is_valid (res)); } @@ -219,15 +245,15 @@ TALER_amount_set_zero (const char *cur, { size_t slen; - slen = strlen (cur); - if (slen >= TALER_CURRENCY_LEN) + if (GNUNET_OK != + TALER_check_currency (cur)) return GNUNET_SYSERR; + slen = strlen (cur); memset (amount, 0, sizeof (struct TALER_Amount)); - memcpy (amount->currency, - cur, - slen); + for (unsigned int i = 0; i<slen; i++) + amount->currency[i] = cur[i]; return GNUNET_OK; } @@ -236,7 +262,10 @@ enum GNUNET_GenericReturnValue TALER_amount_is_valid (const struct TALER_Amount *amount) { if (amount->value > TALER_AMOUNT_MAX_VALUE) + { + GNUNET_break (0); return GNUNET_SYSERR; + } return ('\0' != amount->currency[0]) ? GNUNET_OK : GNUNET_NO; } @@ -680,9 +709,9 @@ TALER_amount_multiply (struct TALER_Amount *result, if (GNUNET_SYSERR == TALER_amount_normalize (&in)) return TALER_AAR_INVALID_NORMALIZATION_FAILED; - memcpy (result->currency, - amount->currency, - TALER_CURRENCY_LEN); + GNUNET_memcpy (result->currency, + amount->currency, + TALER_CURRENCY_LEN); if ( (0 == factor) || ( (0 == in.value) && (0 == in.fraction) ) ) diff --git a/src/util/config.c b/src/util/config.c index c00792469..f5accaad8 100644 --- a/src/util/config.c +++ b/src/util/config.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2014-2020 Taler Systems SA + Copyright (C) 2014-2023 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 @@ -21,7 +21,7 @@ */ #include "platform.h" #include "taler_util.h" - +#include <gnunet/gnunet_json_lib.h> enum GNUNET_GenericReturnValue TALER_config_get_amount (const struct GNUNET_CONFIGURATION_Handle *cfg, @@ -166,3 +166,345 @@ TALER_config_get_currency (const struct GNUNET_CONFIGURATION_Handle *cfg, } return GNUNET_OK; } + + +/** + * Closure for #parse_currencies_cb(). + */ +struct CurrencyParserContext +{ + /** + * Current offset in @e cspecs. + */ + unsigned int num_currencies; + + /** + * Length of the @e cspecs array. + */ + unsigned int len_cspecs; + + /** + * Array of currency specifications (see DD 51). + */ + struct TALER_CurrencySpecification *cspecs; + + /** + * Configuration we are parsing. + */ + const struct GNUNET_CONFIGURATION_Handle *cfg; + + /** + * Set to true if the configuration was malformed. + */ + bool failure; +}; + + +/** + * Function to iterate over section. + * + * @param cls closure with a `struct CurrencyParserContext *` + * @param section name of the section + */ +static void +parse_currencies_cb (void *cls, + const char *section) +{ + struct CurrencyParserContext *cpc = cls; + struct TALER_CurrencySpecification *cspec; + unsigned long long num; + char *str; + + if (cpc->failure) + return; + if (0 != strncasecmp (section, + "currency-", + strlen ("currency-"))) + return; /* not interesting */ + if (GNUNET_YES != + GNUNET_CONFIGURATION_get_value_yesno (cpc->cfg, + section, + "ENABLED")) + return; /* disabled */ + if (cpc->len_cspecs == cpc->num_currencies) + { + GNUNET_array_grow (cpc->cspecs, + cpc->len_cspecs, + cpc->len_cspecs * 2 + 4); + } + cspec = &cpc->cspecs[cpc->num_currencies++]; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cpc->cfg, + section, + "CODE", + &str)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + section, + "CODE"); + cpc->failure = true; + return; + } + if (GNUNET_OK != + TALER_check_currency (str)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "CODE", + "Currency code name given is invalid"); + cpc->failure = true; + GNUNET_free (str); + return; + } + memset (cspec->currency, + 0, + sizeof (cspec->currency)); + /* Already checked in TALER_check_currency(), repeated here + just to make static analysis happy */ + GNUNET_assert (strlen (str) < TALER_CURRENCY_LEN); + strcpy (cspec->currency, + str); + GNUNET_free (str); + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cpc->cfg, + section, + "NAME", + &str)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + section, + "NAME"); + cpc->failure = true; + return; + } + cspec->name = str; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cpc->cfg, + section, + "FRACTIONAL_INPUT_DIGITS", + &num)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + section, + "FRACTIONAL_INPUT_DIGITS"); + cpc->failure = true; + return; + } + if (num > TALER_AMOUNT_FRAC_LEN) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "FRACTIONAL_INPUT_DIGITS", + "Number given is too big"); + cpc->failure = true; + return; + } + cspec->num_fractional_input_digits = num; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cpc->cfg, + section, + "FRACTIONAL_NORMAL_DIGITS", + &num)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + section, + "FRACTIONAL_NORMAL_DIGITS"); + cpc->failure = true; + return; + } + if (num > TALER_AMOUNT_FRAC_LEN) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "FRACTIONAL_NORMAL_DIGITS", + "Number given is too big"); + cpc->failure = true; + return; + } + cspec->num_fractional_normal_digits = num; + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_number (cpc->cfg, + section, + "FRACTIONAL_TRAILING_ZERO_DIGITS", + &num)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + section, + "FRACTIONAL_TRAILING_ZERO_DIGITS"); + cpc->failure = true; + return; + } + if (num > TALER_AMOUNT_FRAC_LEN) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "FRACTIONAL_TRAILING_ZERO_DIGITS", + "Number given is too big"); + cpc->failure = true; + return; + } + cspec->num_fractional_trailing_zero_digits = num; + + if (GNUNET_OK != + GNUNET_CONFIGURATION_get_value_string (cpc->cfg, + section, + "ALT_UNIT_NAMES", + &str)) + { + GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, + section, + "ALT_UNIT_NAMES"); + cpc->failure = true; + return; + } + { + json_error_t err; + + cspec->map_alt_unit_names = json_loads (str, + JSON_REJECT_DUPLICATES, + &err); + GNUNET_free (str); + if (NULL == cspec->map_alt_unit_names) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "ALT_UNIT_NAMES", + err.text); + cpc->failure = true; + return; + } + } + if (GNUNET_OK != + TALER_check_currency_scale_map (cspec->map_alt_unit_names)) + { + GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, + section, + "ALT_UNIT_NAMES", + "invalid map entry detected"); + cpc->failure = true; + json_decref (cspec->map_alt_unit_names); + cspec->map_alt_unit_names = NULL; + return; + } +} + + +enum GNUNET_GenericReturnValue +TALER_check_currency_scale_map (const json_t *map) +{ + /* validate map only maps from decimal numbers to strings! */ + const char *str; + const json_t *val; + bool zf = false; + + if (! json_is_object (map)) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Object required for currency scale map\n"); + return GNUNET_SYSERR; + } + json_object_foreach ((json_t *) map, str, val) + { + int idx; + char dummy; + + if ( (1 != sscanf (str, + "%d%c", + &idx, + &dummy)) || + (idx < -12) || + (idx > 24) || + (! json_is_string (val) ) ) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Invalid entry `%s' in currency scale map\n", + str); + return GNUNET_SYSERR; + } + if (0 == idx) + zf = true; + } + if (! zf) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Entry for 0 missing in currency scale map\n"); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + +enum GNUNET_GenericReturnValue +TALER_CONFIG_parse_currencies (const struct GNUNET_CONFIGURATION_Handle *cfg, + unsigned int *num_currencies, + struct TALER_CurrencySpecification **cspecs) +{ + struct CurrencyParserContext cpc = { + .cfg = cfg + }; + + GNUNET_CONFIGURATION_iterate_sections (cfg, + &parse_currencies_cb, + &cpc); + if (cpc.failure) + { + GNUNET_array_grow (cpc.cspecs, + cpc.len_cspecs, + 0); + return GNUNET_SYSERR; + } + GNUNET_array_grow (cpc.cspecs, + cpc.len_cspecs, + cpc.num_currencies); + *num_currencies = cpc.num_currencies; + *cspecs = cpc.cspecs; + if (0 == *num_currencies) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "No currency formatting specification found! Please check your installation!\n"); + return GNUNET_NO; + } + return GNUNET_OK; +} + + +json_t * +TALER_CONFIG_currency_specs_to_json (const struct + TALER_CurrencySpecification *cspec) +{ + return GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("name", + cspec->name), + /* 'currency' is deprecated as of exchange v18 and merchant v6; + remove this line once current-age > 6*/ + GNUNET_JSON_pack_string ("currency", + cspec->currency), + GNUNET_JSON_pack_uint64 ("num_fractional_input_digits", + cspec->num_fractional_input_digits), + GNUNET_JSON_pack_uint64 ("num_fractional_normal_digits", + cspec->num_fractional_normal_digits), + GNUNET_JSON_pack_uint64 ("num_fractional_trailing_zero_digits", + cspec->num_fractional_trailing_zero_digits), + GNUNET_JSON_pack_object_incref ("alt_unit_names", + cspec->map_alt_unit_names)); +} + + +void +TALER_CONFIG_free_currencies ( + unsigned int num_currencies, + struct TALER_CurrencySpecification cspecs[static num_currencies]) +{ + for (unsigned int i = 0; i<num_currencies; i++) + { + struct TALER_CurrencySpecification *cspec = &cspecs[i]; + + GNUNET_free (cspec->name); + json_decref (cspec->map_alt_unit_names); + } + GNUNET_array_grow (cspecs, + num_currencies, + 0); +} diff --git a/src/util/conversion.c b/src/util/conversion.c new file mode 100644 index 000000000..a7bc63789 --- /dev/null +++ b/src/util/conversion.c @@ -0,0 +1,405 @@ +/* + This file is part of TALER + Copyright (C) 2023 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 conversion.c + * @brief helper routines to run some external JSON-to-JSON converter + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_util.h" +#include <gnunet/gnunet_util_lib.h> + + +struct TALER_JSON_ExternalConversion +{ + /** + * Callback to call with the result. + */ + TALER_JSON_JsonCallback cb; + + /** + * Closure for @e cb. + */ + void *cb_cls; + + /** + * Handle to the helper process. + */ + struct GNUNET_OS_Process *helper; + + /** + * Pipe for the stdin of the @e helper. + */ + struct GNUNET_DISK_FileHandle *chld_stdin; + + /** + * Pipe for the stdout of the @e helper. + */ + struct GNUNET_DISK_FileHandle *chld_stdout; + + /** + * Handle to wait on the child to terminate. + */ + struct GNUNET_ChildWaitHandle *cwh; + + /** + * Task to read JSON output from the child. + */ + struct GNUNET_SCHEDULER_Task *read_task; + + /** + * Task to send JSON input to the child. + */ + struct GNUNET_SCHEDULER_Task *write_task; + + /** + * Buffer with data we need to send to the helper. + */ + void *write_buf; + + /** + * Buffer for reading data from the helper. + */ + void *read_buf; + + /** + * Total length of @e write_buf. + */ + size_t write_size; + + /** + * Current write position in @e write_buf. + */ + size_t write_pos; + + /** + * Current size of @a read_buf. + */ + size_t read_size; + + /** + * Current offset in @a read_buf. + */ + size_t read_pos; + +}; + + +/** + * Function called when we can read more data from + * the child process. + * + * @param cls our `struct TALER_JSON_ExternalConversion *` + */ +static void +read_cb (void *cls) +{ + struct TALER_JSON_ExternalConversion *ec = cls; + + ec->read_task = NULL; + while (1) + { + ssize_t ret; + + if (ec->read_size == ec->read_pos) + { + /* Grow input buffer */ + size_t ns; + void *tmp; + + ns = GNUNET_MAX (2 * ec->read_size, + 1024); + if (ns > GNUNET_MAX_MALLOC_CHECKED) + ns = GNUNET_MAX_MALLOC_CHECKED; + if (ec->read_size == ns) + { + /* Helper returned more than 40 MB of data! Stop reading! */ + GNUNET_break (0); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_file_close (ec->chld_stdin)); + return; + } + tmp = GNUNET_malloc_large (ns); + if (NULL == tmp) + { + /* out of memory, also stop reading */ + GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, + "malloc"); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_file_close (ec->chld_stdin)); + return; + } + GNUNET_memcpy (tmp, + ec->read_buf, + ec->read_pos); + GNUNET_free (ec->read_buf); + ec->read_buf = tmp; + ec->read_size = ns; + } + ret = GNUNET_DISK_file_read (ec->chld_stdout, + ec->read_buf + ec->read_pos, + ec->read_size - ec->read_pos); + if (ret < 0) + { + if ( (EAGAIN != errno) && + (EWOULDBLOCK != errno) && + (EINTR != errno) ) + { + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "read"); + return; + } + break; + } + if (0 == ret) + { + /* regular end of stream, good! */ + return; + } + GNUNET_assert (ec->read_size >= ec->read_pos + ret); + ec->read_pos += ret; + } + ec->read_task + = GNUNET_SCHEDULER_add_read_file ( + GNUNET_TIME_UNIT_FOREVER_REL, + ec->chld_stdout, + &read_cb, + ec); +} + + +/** + * Function called when we can write more data to + * the child process. + * + * @param cls our `struct TALER_JSON_ExternalConversion *` + */ +static void +write_cb (void *cls) +{ + struct TALER_JSON_ExternalConversion *ec = cls; + ssize_t ret; + + ec->write_task = NULL; + while (ec->write_size > ec->write_pos) + { + ret = GNUNET_DISK_file_write (ec->chld_stdin, + ec->write_buf + ec->write_pos, + ec->write_size - ec->write_pos); + if (ret < 0) + { + if ( (EAGAIN != errno) && + (EINTR != errno) ) + GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, + "write"); + break; + } + if (0 == ret) + { + GNUNET_break (0); + break; + } + GNUNET_assert (ec->write_size >= ec->write_pos + ret); + ec->write_pos += ret; + } + if ( (ec->write_size > ec->write_pos) && + ( (EAGAIN == errno) || + (EWOULDBLOCK == errno) || + (EINTR == errno) ) ) + { + ec->write_task + = GNUNET_SCHEDULER_add_write_file ( + GNUNET_TIME_UNIT_FOREVER_REL, + ec->chld_stdin, + &write_cb, + ec); + } + else + { + GNUNET_break (GNUNET_OK == + GNUNET_DISK_file_close (ec->chld_stdin)); + ec->chld_stdin = NULL; + } +} + + +/** + * Defines a GNUNET_ChildCompletedCallback which is sent back + * upon death or completion of a child process. + * + * @param cls handle for the callback + * @param type type of the process + * @param exit_code status code of the process + * + */ +static void +child_done_cb (void *cls, + enum GNUNET_OS_ProcessStatusType type, + long unsigned int exit_code) +{ + struct TALER_JSON_ExternalConversion *ec = cls; + json_t *j = NULL; + json_error_t err; + + ec->cwh = NULL; + if (NULL != ec->read_task) + { + GNUNET_SCHEDULER_cancel (ec->read_task); + /* We could get the process termination notification before having drained + the read buffer. So drain it now, just in case. */ + read_cb (ec); + } + GNUNET_log (GNUNET_ERROR_TYPE_INFO, + "Conversion helper exited with status %d and code %llu after outputting %llu bytes of data\n", + (int) type, + (unsigned long long) exit_code, + (unsigned long long) ec->read_pos); + GNUNET_OS_process_destroy (ec->helper); + ec->helper = NULL; + if (0 != ec->read_pos) + { + j = json_loadb (ec->read_buf, + ec->read_pos, + JSON_REJECT_DUPLICATES, + &err); + if (NULL == j) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to parse JSON from helper at %d: %s\n", + err.position, + err.text); + } + } + ec->cb (ec->cb_cls, + type, + exit_code, + j); + json_decref (j); + TALER_JSON_external_conversion_stop (ec); +} + + +struct TALER_JSON_ExternalConversion * +TALER_JSON_external_conversion_start (const json_t *input, + TALER_JSON_JsonCallback cb, + void *cb_cls, + const char *binary, + ...) +{ + struct TALER_JSON_ExternalConversion *ec; + struct GNUNET_DISK_PipeHandle *pipe_stdin; + struct GNUNET_DISK_PipeHandle *pipe_stdout; + va_list ap; + + ec = GNUNET_new (struct TALER_JSON_ExternalConversion); + ec->cb = cb; + ec->cb_cls = cb_cls; + pipe_stdin = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_READ); + GNUNET_assert (NULL != pipe_stdin); + pipe_stdout = GNUNET_DISK_pipe (GNUNET_DISK_PF_BLOCKING_WRITE); + GNUNET_assert (NULL != pipe_stdout); + va_start (ap, + binary); + ec->helper = GNUNET_OS_start_process_va (GNUNET_OS_INHERIT_STD_ERR, + pipe_stdin, + pipe_stdout, + NULL, + binary, + ap); + va_end (ap); + if (NULL == ec->helper) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Failed to run conversion helper `%s'\n", + binary); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_pipe_close (pipe_stdin)); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_pipe_close (pipe_stdout)); + GNUNET_free (ec); + return NULL; + } + ec->chld_stdin = + GNUNET_DISK_pipe_detach_end (pipe_stdin, + GNUNET_DISK_PIPE_END_WRITE); + ec->chld_stdout = + GNUNET_DISK_pipe_detach_end (pipe_stdout, + GNUNET_DISK_PIPE_END_READ); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_pipe_close (pipe_stdin)); + GNUNET_break (GNUNET_OK == + GNUNET_DISK_pipe_close (pipe_stdout)); + ec->write_buf = json_dumps (input, JSON_COMPACT); + ec->write_size = strlen (ec->write_buf); + ec->read_task + = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + ec->chld_stdout, + &read_cb, + ec); + ec->write_task + = GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL, + ec->chld_stdin, + &write_cb, + ec); + ec->cwh = GNUNET_wait_child (ec->helper, + &child_done_cb, + ec); + return ec; +} + + +void +TALER_JSON_external_conversion_stop ( + struct TALER_JSON_ExternalConversion *ec) +{ + if (NULL != ec->cwh) + { + GNUNET_wait_child_cancel (ec->cwh); + ec->cwh = NULL; + } + if (NULL != ec->helper) + { + GNUNET_break (0 == + GNUNET_OS_process_kill (ec->helper, + SIGKILL)); + GNUNET_OS_process_destroy (ec->helper); + } + if (NULL != ec->read_task) + { + GNUNET_SCHEDULER_cancel (ec->read_task); + ec->read_task = NULL; + } + if (NULL != ec->write_task) + { + GNUNET_SCHEDULER_cancel (ec->write_task); + ec->write_task = NULL; + } + if (NULL != ec->chld_stdin) + { + GNUNET_break (GNUNET_OK == + GNUNET_DISK_file_close (ec->chld_stdin)); + ec->chld_stdin = NULL; + } + if (NULL != ec->chld_stdout) + { + GNUNET_break (GNUNET_OK == + GNUNET_DISK_file_close (ec->chld_stdout)); + ec->chld_stdout = NULL; + } + GNUNET_free (ec->read_buf); + free (ec->write_buf); + GNUNET_free (ec); +} diff --git a/src/util/crypto.c b/src/util/crypto.c index bb14b6cdc..4735af3b0 100644 --- a/src/util/crypto.c +++ b/src/util/crypto.c @@ -85,7 +85,9 @@ TALER_test_coin_valid (const struct TALER_CoinPublicInfo *coin_public_info, #endif TALER_coin_pub_hash (&coin_public_info->coin_pub, - &coin_public_info->h_age_commitment, + coin_public_info->no_age_commitment + ? NULL + : &coin_public_info->h_age_commitment, &c_hash); if (GNUNET_OK != @@ -212,7 +214,7 @@ TALER_planchet_secret_to_transfer_priv ( void TALER_cs_withdraw_nonce_derive ( const struct TALER_PlanchetMasterSecretP *ps, - struct TALER_CsNonce *nonce) + struct GNUNET_CRYPTO_CsSessionNonce *nonce) { GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_kdf (nonce, @@ -230,7 +232,7 @@ void TALER_cs_refresh_nonce_derive ( const struct TALER_RefreshMasterSecretP *rms, uint32_t coin_num_salt, - struct TALER_CsNonce *nonce) + struct GNUNET_CRYPTO_CsSessionNonce *nonce) { uint32_t be_salt = htonl (coin_num_salt); @@ -248,10 +250,31 @@ TALER_cs_refresh_nonce_derive ( } +void +TALER_rsa_pub_hash (const struct GNUNET_CRYPTO_RsaPublicKey *rsa, + struct TALER_RsaPubHashP *h_rsa) +{ + GNUNET_CRYPTO_rsa_public_key_hash (rsa, + &h_rsa->hash); + +} + + +void +TALER_cs_pub_hash (const struct GNUNET_CRYPTO_CsPublicKey *cs, + struct TALER_CsPubHashP *h_cs) +{ + GNUNET_CRYPTO_hash (cs, + sizeof(*cs), + &h_cs->hash); +} + + enum GNUNET_GenericReturnValue TALER_planchet_prepare (const struct TALER_DenominationPublicKey *dk, const struct TALER_ExchangeWithdrawValues *alg_values, - const union TALER_DenominationBlindingKeyP *bks, + const union GNUNET_CRYPTO_BlindingSecretP *bks, + const union GNUNET_CRYPTO_BlindSessionNonce *nonce, const struct TALER_CoinSpendPrivateKeyP *coin_priv, const struct TALER_AgeCommitmentHash *ach, struct TALER_CoinPubHashP *c_hash, @@ -260,12 +283,14 @@ TALER_planchet_prepare (const struct TALER_DenominationPublicKey *dk, { struct TALER_CoinSpendPublicKeyP coin_pub; - GNUNET_assert (alg_values->cipher == dk->cipher); + GNUNET_assert (alg_values->blinding_inputs->cipher == + dk->bsign_pub_key->cipher); GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv, &coin_pub.eddsa_pub); if (GNUNET_OK != TALER_denom_blind (dk, bks, + nonce, ach, &coin_pub, alg_values, @@ -292,15 +317,21 @@ enum GNUNET_GenericReturnValue TALER_planchet_to_coin ( const struct TALER_DenominationPublicKey *dk, const struct TALER_BlindedDenominationSignature *blind_sig, - const union TALER_DenominationBlindingKeyP *bks, + const union GNUNET_CRYPTO_BlindingSecretP *bks, const struct TALER_CoinSpendPrivateKeyP *coin_priv, const struct TALER_AgeCommitmentHash *ach, const struct TALER_CoinPubHashP *c_hash, const struct TALER_ExchangeWithdrawValues *alg_values, struct TALER_FreshCoin *coin) { - if ( (dk->cipher != blind_sig->cipher) || - (dk->cipher != alg_values->cipher) ) + if (dk->bsign_pub_key->cipher != + blind_sig->blinded_sig->cipher) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + if (dk->bsign_pub_key->cipher != + alg_values->blinding_inputs->cipher) { GNUNET_break_op (0); return GNUNET_SYSERR; @@ -442,7 +473,7 @@ TALER_coin_pub_hash (const struct TALER_CoinSpendPublicKeyP *coin_pub, } -enum GNUNET_GenericReturnValue +void TALER_coin_ev_hash (const struct TALER_BlindedPlanchet *blinded_planchet, const struct TALER_DenominationHashP *denom_hash, struct TALER_BlindedCoinHashP *bch) @@ -457,7 +488,56 @@ TALER_coin_ev_hash (const struct TALER_BlindedPlanchet *blinded_planchet, hash_context); GNUNET_CRYPTO_hash_context_finish (hash_context, &bch->hash); - return GNUNET_OK; +} + + +GNUNET_NETWORK_STRUCT_BEGIN +/** + * Structure we hash to compute the group key for + * a denomination group. + */ +struct DenominationGroupP +{ + /** + * Value of coins in this denomination group. + */ + struct TALER_AmountNBO value; + + /** + * Fee structure for all coins in the group. + */ + struct TALER_DenomFeeSetNBOP fees; + + /** + * Age mask for the denomiation, in NBO. + */ + uint32_t age_mask GNUNET_PACKED; + + /** + * Cipher used for the denomination, in NBO. + */ + uint32_t cipher GNUNET_PACKED; +}; +GNUNET_NETWORK_STRUCT_END + + +void +TALER_denomination_group_get_key ( + const struct TALER_DenominationGroup *dg, + struct GNUNET_HashCode *key) +{ + struct DenominationGroupP dgp = { + .age_mask = htonl (dg->age_mask.bits), + .cipher = htonl (dg->cipher) + }; + + TALER_amount_hton (&dgp.value, + &dg->value); + TALER_denom_fee_set_hton (&dgp.fees, + &dg->fees); + GNUNET_CRYPTO_hash (&dgp, + sizeof (dgp), + key); } diff --git a/src/util/crypto_confirmation.c b/src/util/crypto_confirmation.c index c5a674501..99552f150 100644 --- a/src/util/crypto_confirmation.c +++ b/src/util/crypto_confirmation.c @@ -81,18 +81,19 @@ compute_totp (struct GNUNET_TIME_Timestamp ts, gcry_md_open (&md, GCRY_MD_SHA1, GCRY_MD_FLAG_HMAC)); - gcry_md_setkey (md, - key, - key_size); + GNUNET_assert (GPG_ERR_NO_ERROR == + gcry_md_setkey (md, + key, + key_size)); gcry_md_write (md, &ctr, sizeof (ctr)); mc = gcry_md_read (md, GCRY_MD_SHA1); GNUNET_assert (NULL != mc); - memcpy (hmac, - mc, - sizeof (hmac)); + GNUNET_memcpy (hmac, + mc, + sizeof (hmac)); gcry_md_close (md); } @@ -102,7 +103,7 @@ compute_totp (struct GNUNET_TIME_Timestamp ts, offset = hmac[sizeof (hmac) - 1] & 0x0f; for (int count = 0; count < 4; count++) - code |= hmac[offset + 3 - count] << (8 * count); + code |= ((uint32_t) hmac[offset + 3 - count]) << (8 * count); code &= 0x7fffffff; /* always use 8 digits (maximum) */ code = code % 100000000; @@ -111,20 +112,11 @@ compute_totp (struct GNUNET_TIME_Timestamp ts, } -/** - * Compute RFC 3548 base32 decoding of @a val and write - * result to @a udata. - * - * @param val value to decode - * @param val_size number of bytes in @a val - * @param key is the val in bits - * @param key_len is the size of @a key - */ -static int -base32decode (const char *val, - size_t val_size, - void *key, - size_t key_len) +int +TALER_rfc3548_base32decode (const char *val, + size_t val_size, + void *key, + size_t key_len) { /** * 32 characters for decoding, using RFC 3548. @@ -141,13 +133,21 @@ base32decode (const char *val, if ((rpos < val_size) && (vbit < 8)) { char c = val[rpos++]; - if (c == '=') // padding character + + if (c == '=') { - break; + /* padding character */ + if (rpos == val_size) + break; /* Ok, 1x '=' padding is allowed */ + if ( ('=' == val[rpos]) && + (rpos + 1 == val_size) ) + break; /* Ok, 2x '=' padding is allowed */ + return -1; /* invalid padding */ } const char *p = strchr (decTable__, toupper (c)); if (! p) - { // invalid character + { + /* invalid character */ return -1; } bits = (bits << 5) | (p - decTable__); @@ -189,7 +189,7 @@ executive_totp (void *h_key, if (NULL == ret) { GNUNET_asprintf (&ret, - "%llu", + "%08llu", (unsigned long long) code); } else @@ -197,7 +197,7 @@ executive_totp (void *h_key, char *tmp; GNUNET_asprintf (&tmp, - "%s\n%llu", + "%s\n%08llu", ret, (unsigned long long) code); GNUNET_free (ret); @@ -225,10 +225,10 @@ TALER_build_pos_confirmation (const char *pos_key, return NULL; key_len = pos_key_length * 5 / 8; key = GNUNET_malloc (key_len); - dret = base32decode (pos_key, - pos_key_length, - key, - key_len); + dret = TALER_rfc3548_base32decode (pos_key, + pos_key_length, + key, + key_len); if (-1 == dret) { GNUNET_free (key); @@ -261,6 +261,13 @@ TALER_build_pos_confirmation (const char *pos_key, struct GNUNET_HashCode hkey; struct TALER_AmountNBO ntotal; + if ( (NULL == total) || + (GNUNET_YES != + TALER_amount_is_valid (total) ) ) + { + GNUNET_break_op (0); + return NULL; + } TALER_amount_hton (&ntotal, total); GNUNET_assert (GNUNET_YES == diff --git a/src/util/crypto_contract.c b/src/util/crypto_contract.c index 3bfe9eb89..bec34c983 100644 --- a/src/util/crypto_contract.c +++ b/src/util/crypto_contract.c @@ -131,9 +131,9 @@ blob_encrypt (const struct NonceP *nonce, + data_size; *res_size = ciphertext_size; *res = GNUNET_malloc (ciphertext_size); - memcpy (*res, - nonce, - crypto_secretbox_NONCEBYTES); + GNUNET_memcpy (*res, + nonce, + crypto_secretbox_NONCEBYTES); GNUNET_assert (0 == crypto_secretbox_easy (*res + crypto_secretbox_NONCEBYTES, data, @@ -274,9 +274,9 @@ TALER_CRYPTO_contract_encrypt_for_merge ( hdr->header.ctype = htonl (TALER_EXCHANGE_CONTRACT_PAYMENT_OFFER); hdr->header.clen = htonl ((uint32_t) clen); hdr->merge_priv = *merge_priv; - memcpy (&hdr[1], - xbuf, - cbuf_size); + GNUNET_memcpy (&hdr[1], + xbuf, + cbuf_size); GNUNET_free (xbuf); GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, &nonce, @@ -423,9 +423,9 @@ TALER_CRYPTO_contract_encrypt_for_deposit ( hdr = GNUNET_malloc (sizeof (*hdr) + cbuf_size); hdr->ctype = htonl (TALER_EXCHANGE_CONTRACT_PAYMENT_REQUEST); hdr->clen = htonl ((uint32_t) clen); - memcpy (&hdr[1], - xbuf, - cbuf_size); + GNUNET_memcpy (&hdr[1], + xbuf, + cbuf_size); GNUNET_free (xbuf); GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE, &nonce, @@ -441,12 +441,12 @@ TALER_CRYPTO_contract_encrypt_for_deposit ( GNUNET_free (hdr); /* prepend purse_pub */ *econtract = GNUNET_malloc (xecontract_size + sizeof (*purse_pub)); - memcpy (*econtract, - purse_pub, - sizeof (*purse_pub)); - memcpy (sizeof (*purse_pub) + *econtract, - xecontract, - xecontract_size); + GNUNET_memcpy (*econtract, + purse_pub, + sizeof (*purse_pub)); + GNUNET_memcpy (sizeof (*purse_pub) + *econtract, + xecontract, + xecontract_size); *econtract_size = xecontract_size + sizeof (*purse_pub); GNUNET_free (xecontract); } @@ -573,9 +573,9 @@ TALER_CRYPTO_kyc_attributes_encrypt ( cbuf_size = compressBound (clen); xbuf = GNUNET_malloc (cbuf_size + sizeof (uint32_t)); belen = htonl ((uint32_t) clen); - memcpy (xbuf, - &belen, - sizeof (belen)); + GNUNET_memcpy (xbuf, + &belen, + sizeof (belen)); ret = compress (xbuf + 4, &cbuf_size, (const Bytef *) cstr, @@ -623,9 +623,9 @@ TALER_CRYPTO_kyc_attributes_decrypt ( GNUNET_break_op (0); return NULL; } - memcpy (&belen, - xhdr, - sizeof (belen)); + GNUNET_memcpy (&belen, + xhdr, + sizeof (belen)); clen = ntohl (belen); if (clen >= GNUNET_MAX_MALLOC_CHECKED) { diff --git a/src/util/crypto_helper_cs.c b/src/util/crypto_helper_cs.c index 5f7d3d6f9..4c4a56feb 100644 --- a/src/util/crypto_helper_cs.c +++ b/src/util/crypto_helper_cs.c @@ -113,21 +113,27 @@ try_connect (struct TALER_CRYPTO_CsDenominationHelper *dh) struct TALER_CRYPTO_CsDenominationHelper * TALER_CRYPTO_helper_cs_connect ( const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, TALER_CRYPTO_CsDenominationKeyStatusCallback dkc, void *dkc_cls) { struct TALER_CRYPTO_CsDenominationHelper *dh; char *unixpath; + char *secname; + GNUNET_asprintf (&secname, + "%s-secmod-cs", + section); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, - "taler-exchange-secmod-cs", + secname, "UNIXPATH", &unixpath)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-cs", + secname, "UNIXPATH"); + GNUNET_free (secname); return NULL; } /* we use >= here because we want the sun_path to always @@ -135,12 +141,14 @@ TALER_CRYPTO_helper_cs_connect ( if (strlen (unixpath) >= sizeof (dh->sa.sun_path)) { GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-cs", + secname, "UNIXPATH", "path too long"); GNUNET_free (unixpath); + GNUNET_free (secname); return NULL; } + GNUNET_free (secname); dh = GNUNET_new (struct TALER_CRYPTO_CsDenominationHelper); dh->dkc = dkc; dh->dkc_cls = dkc_cls; @@ -201,13 +209,18 @@ handle_mt_avail (struct TALER_CRYPTO_CsDenominationHelper *dh, } { - struct TALER_DenominationPublicKey denom_pub; + struct GNUNET_CRYPTO_BlindSignPublicKey *bsign_pub; struct TALER_CsPubHashP h_cs; - denom_pub.cipher = TALER_DENOMINATION_CS; - denom_pub.details.cs_public_key = kan->denom_pub; + bsign_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey); + bsign_pub->cipher = GNUNET_CRYPTO_BSA_CS; + bsign_pub->rc = 1; + bsign_pub->details.cs_public_key = kan->denom_pub; - TALER_cs_pub_hash (&denom_pub.details.cs_public_key, &h_cs); + GNUNET_CRYPTO_hash (&bsign_pub->details.cs_public_key, + sizeof (bsign_pub->details.cs_public_key), + &bsign_pub->pub_key_hash); + h_cs.hash = bsign_pub->pub_key_hash; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received CS key %s (%s)\n", GNUNET_h2s (&h_cs.hash), @@ -222,7 +235,7 @@ handle_mt_avail (struct TALER_CRYPTO_CsDenominationHelper *dh, &kan->secm_sig)) { GNUNET_break_op (0); - TALER_denom_pub_free (&denom_pub); + GNUNET_CRYPTO_blind_sign_pub_decref (bsign_pub); return GNUNET_SYSERR; } dh->dkc (dh->dkc_cls, @@ -230,10 +243,10 @@ handle_mt_avail (struct TALER_CRYPTO_CsDenominationHelper *dh, GNUNET_TIME_timestamp_ntoh (kan->anchor_time), GNUNET_TIME_relative_ntoh (kan->duration_withdraw), &h_cs, - &denom_pub, + bsign_pub, &kan->secm_pub, &kan->secm_sig); - TALER_denom_pub_free (&denom_pub); + GNUNET_CRYPTO_blind_sign_pub_decref (bsign_pub); } return GNUNET_OK; } @@ -387,10 +400,10 @@ TALER_CRYPTO_helper_cs_sign ( { enum TALER_ErrorCode ec = TALER_EC_INVALID; const struct TALER_CsPubHashP *h_cs = req->h_cs; - const struct TALER_BlindedCsPlanchet *blinded_planchet = - req->blinded_planchet; - bs->cipher = TALER_DENOMINATION_INVALID; + memset (bs, + 0, + sizeof (*bs)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting signature process\n"); if (GNUNET_OK != @@ -412,7 +425,7 @@ TALER_CRYPTO_helper_cs_sign ( sr->header.type = htons (TALER_HELPER_CS_MT_REQ_SIGN); sr->for_melt = htonl (for_melt ? 1 : 0); sr->h_cs = *h_cs; - sr->planchet = *blinded_planchet; + sr->message = *req->blinded_planchet; if (GNUNET_OK != TALER_crypto_helper_send_all (dh->sock, buf, @@ -495,13 +508,18 @@ more: { const struct TALER_CRYPTO_SignResponse *sr = (const struct TALER_CRYPTO_SignResponse *) buf; + struct GNUNET_CRYPTO_BlindedSignature *blinded_sig; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received signature\n"); ec = TALER_EC_NONE; finished = true; - bs->cipher = TALER_DENOMINATION_CS; - bs->details.blinded_cs_answer = sr->cs_answer; + blinded_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature); + blinded_sig->cipher = GNUNET_CRYPTO_BSA_CS; + blinded_sig->rc = 1; + blinded_sig->details.blinded_cs_answer.b = ntohl (sr->b); + blinded_sig->details.blinded_cs_answer.s_scalar = sr->cs_answer; + bs->blinded_sig = blinded_sig; break; } case TALER_HELPER_CS_MT_RES_SIGN_FAILURE: @@ -611,11 +629,11 @@ enum TALER_ErrorCode TALER_CRYPTO_helper_cs_r_derive (struct TALER_CRYPTO_CsDenominationHelper *dh, const struct TALER_CRYPTO_CsDeriveRequest *cdr, bool for_melt, - struct TALER_DenominationCSPublicRPairP *crp) + struct GNUNET_CRYPTO_CSPublicRPairP *crp) { enum TALER_ErrorCode ec = TALER_EC_INVALID; const struct TALER_CsPubHashP *h_cs = cdr->h_cs; - const struct TALER_CsNonce *nonce = cdr->nonce; + const struct GNUNET_CRYPTO_CsSessionNonce *nonce = cdr->nonce; memset (crp, 0, @@ -795,10 +813,10 @@ more: enum TALER_ErrorCode TALER_CRYPTO_helper_cs_batch_sign ( struct TALER_CRYPTO_CsDenominationHelper *dh, - const struct TALER_CRYPTO_CsSignRequest *reqs, unsigned int reqs_length, + const struct TALER_CRYPTO_CsSignRequest reqs[static reqs_length], bool for_melt, - struct TALER_BlindedDenominationSignature *bss) + struct TALER_BlindedDenominationSignature bss[static reqs_length]) { enum TALER_ErrorCode ec = TALER_EC_INVALID; unsigned int rpos; @@ -854,7 +872,7 @@ TALER_CRYPTO_helper_cs_batch_sign ( csm->header.type = htons (TALER_HELPER_CS_MT_REQ_SIGN); csm->for_melt = htonl (for_melt ? 1 : 0); csm->h_cs = *csr->h_cs; - csm->planchet = *csr->blinded_planchet; + csm->message = *csr->blinded_planchet; wbuf += sizeof (*csm); } GNUNET_assert (wbuf == &obuf[mlen]); @@ -945,12 +963,17 @@ more: { const struct TALER_CRYPTO_SignResponse *sr = (const struct TALER_CRYPTO_SignResponse *) buf; - + struct GNUNET_CRYPTO_BlindedSignature *blinded_sig; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received %u signature\n", wpos); - bss[wpos].cipher = TALER_DENOMINATION_CS; - bss[wpos].details.blinded_cs_answer = sr->cs_answer; + blinded_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature); + blinded_sig->cipher = GNUNET_CRYPTO_BSA_CS; + blinded_sig->rc = 1; + blinded_sig->details.blinded_cs_answer.b = ntohl (sr->b); + blinded_sig->details.blinded_cs_answer.s_scalar = sr->cs_answer; + + bss[wpos].blinded_sig = blinded_sig; wpos++; if (wpos == rend) { @@ -1040,10 +1063,10 @@ more: enum TALER_ErrorCode TALER_CRYPTO_helper_cs_r_batch_derive ( struct TALER_CRYPTO_CsDenominationHelper *dh, - const struct TALER_CRYPTO_CsDeriveRequest *cdrs, unsigned int cdrs_length, + const struct TALER_CRYPTO_CsDeriveRequest cdrs[static cdrs_length], bool for_melt, - struct TALER_DenominationCSPublicRPairP *crps) + struct GNUNET_CRYPTO_CSPublicRPairP crps[static cdrs_length]) { enum TALER_ErrorCode ec = TALER_EC_INVALID; unsigned int rpos; diff --git a/src/util/crypto_helper_esign.c b/src/util/crypto_helper_esign.c index 5a9ad74e2..e044d31d1 100644 --- a/src/util/crypto_helper_esign.c +++ b/src/util/crypto_helper_esign.c @@ -111,21 +111,28 @@ try_connect (struct TALER_CRYPTO_ExchangeSignHelper *esh) struct TALER_CRYPTO_ExchangeSignHelper * TALER_CRYPTO_helper_esign_connect ( const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, TALER_CRYPTO_ExchangeKeyStatusCallback ekc, void *ekc_cls) { struct TALER_CRYPTO_ExchangeSignHelper *esh; char *unixpath; + char *secname; + + GNUNET_asprintf (&secname, + "%s-secmod-eddsa", + section); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, - "taler-exchange-secmod-eddsa", + secname, "UNIXPATH", &unixpath)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-eddsa", + secname, "UNIXPATH"); + GNUNET_free (secname); return NULL; } /* we use >= here because we want the sun_path to always @@ -133,12 +140,14 @@ TALER_CRYPTO_helper_esign_connect ( if (strlen (unixpath) >= sizeof (esh->sa.sun_path)) { GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-eddsa", + secname, "UNIXPATH", "path too long"); GNUNET_free (unixpath); + GNUNET_free (secname); return NULL; } + GNUNET_free (secname); esh = GNUNET_new (struct TALER_CRYPTO_ExchangeSignHelper); esh->ekc = ekc; esh->ekc_cls = ekc_cls; @@ -357,9 +366,9 @@ TALER_CRYPTO_helper_esign_sign_ ( sr->header.size = htons (sizeof (buf)); sr->header.type = htons (TALER_HELPER_EDDSA_MT_REQ_SIGN); sr->reserved = htonl (0); - memcpy (&sr->purpose, - purpose, - purpose_size); + GNUNET_memcpy (&sr->purpose, + purpose, + purpose_size); if (GNUNET_OK != TALER_crypto_helper_send_all (esh->sock, buf, diff --git a/src/util/crypto_helper_rsa.c b/src/util/crypto_helper_rsa.c index efded50a1..e23e12a88 100644 --- a/src/util/crypto_helper_rsa.c +++ b/src/util/crypto_helper_rsa.c @@ -113,21 +113,28 @@ try_connect (struct TALER_CRYPTO_RsaDenominationHelper *dh) struct TALER_CRYPTO_RsaDenominationHelper * TALER_CRYPTO_helper_rsa_connect ( const struct GNUNET_CONFIGURATION_Handle *cfg, + const char *section, TALER_CRYPTO_RsaDenominationKeyStatusCallback dkc, void *dkc_cls) { struct TALER_CRYPTO_RsaDenominationHelper *dh; char *unixpath; + char *secname; + + GNUNET_asprintf (&secname, + "%s-secmod-rsa", + section); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, - "taler-exchange-secmod-rsa", + secname, "UNIXPATH", &unixpath)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-rsa", + secname, "UNIXPATH"); + GNUNET_free (secname); return NULL; } /* we use >= here because we want the sun_path to always @@ -135,12 +142,14 @@ TALER_CRYPTO_helper_rsa_connect ( if (strlen (unixpath) >= sizeof (dh->sa.sun_path)) { GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-rsa", + secname, "UNIXPATH", "path too long"); GNUNET_free (unixpath); + GNUNET_free (secname); return NULL; } + GNUNET_free (secname); dh = GNUNET_new (struct TALER_CRYPTO_RsaDenominationHelper); dh->dkc = dkc; dh->dkc_cls = dkc_cls; @@ -203,23 +212,27 @@ handle_mt_avail (struct TALER_CRYPTO_RsaDenominationHelper *dh, } { - struct TALER_DenominationPublicKey denom_pub; + struct GNUNET_CRYPTO_BlindSignPublicKey *bs_pub; struct TALER_RsaPubHashP h_rsa; - denom_pub.cipher = TALER_DENOMINATION_RSA; - denom_pub.details.rsa_public_key + bs_pub = GNUNET_new (struct GNUNET_CRYPTO_BlindSignPublicKey); + bs_pub->cipher = GNUNET_CRYPTO_BSA_RSA; + bs_pub->details.rsa_public_key = GNUNET_CRYPTO_rsa_public_key_decode (buf, ntohs (kan->pub_size)); - if (NULL == denom_pub.details.rsa_public_key) + if (NULL == bs_pub->details.rsa_public_key) { GNUNET_break_op (0); + GNUNET_free (bs_pub); return GNUNET_SYSERR; } - GNUNET_CRYPTO_rsa_public_key_hash (denom_pub.details.rsa_public_key, - &h_rsa.hash); + bs_pub->rc = 1; + GNUNET_CRYPTO_rsa_public_key_hash (bs_pub->details.rsa_public_key, + &bs_pub->pub_key_hash); + h_rsa.hash = bs_pub->pub_key_hash; GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received RSA key %s (%s)\n", - GNUNET_h2s (&h_rsa.hash), + GNUNET_h2s (&bs_pub->pub_key_hash), section_name); if (GNUNET_OK != TALER_exchange_secmod_rsa_verify ( @@ -231,7 +244,7 @@ handle_mt_avail (struct TALER_CRYPTO_RsaDenominationHelper *dh, &kan->secm_sig)) { GNUNET_break_op (0); - TALER_denom_pub_free (&denom_pub); + GNUNET_CRYPTO_blind_sign_pub_decref (bs_pub); return GNUNET_SYSERR; } dh->dkc (dh->dkc_cls, @@ -239,10 +252,10 @@ handle_mt_avail (struct TALER_CRYPTO_RsaDenominationHelper *dh, GNUNET_TIME_timestamp_ntoh (kan->anchor_time), GNUNET_TIME_relative_ntoh (kan->duration_withdraw), &h_rsa, - &denom_pub, + bs_pub, &kan->secm_pub, &kan->secm_sig); - TALER_denom_pub_free (&denom_pub); + GNUNET_CRYPTO_blind_sign_pub_decref (bs_pub); } return GNUNET_OK; } @@ -395,7 +408,9 @@ TALER_CRYPTO_helper_rsa_sign ( { enum TALER_ErrorCode ec = TALER_EC_INVALID; - bs->cipher = TALER_DENOMINATION_INVALID; + memset (bs, + 0, + sizeof (*bs)); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting signature process\n"); if (GNUNET_OK != @@ -417,9 +432,9 @@ TALER_CRYPTO_helper_rsa_sign ( sr->header.type = htons (TALER_HELPER_RSA_MT_REQ_SIGN); sr->reserved = htonl (0); sr->h_rsa = *rsr->h_rsa; - memcpy (&sr[1], - rsr->msg, - rsr->msg_size); + GNUNET_memcpy (&sr[1], + rsr->msg, + rsr->msg_size); if (GNUNET_OK != TALER_crypto_helper_send_all (dh->sock, buf, @@ -503,6 +518,7 @@ more: const struct TALER_CRYPTO_SignResponse *sr = (const struct TALER_CRYPTO_SignResponse *) buf; struct GNUNET_CRYPTO_RsaSignature *rsa_signature; + struct GNUNET_CRYPTO_BlindedSignature *blind_sig; rsa_signature = GNUNET_CRYPTO_rsa_signature_decode ( &sr[1], @@ -518,8 +534,11 @@ more: "Received signature\n"); ec = TALER_EC_NONE; finished = true; - bs->cipher = TALER_DENOMINATION_RSA; - bs->details.blinded_rsa_signature = rsa_signature; + blind_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature); + blind_sig->cipher = GNUNET_CRYPTO_BSA_RSA; + blind_sig->rc = 1; + blind_sig->details.blinded_rsa_signature = rsa_signature; + bs->blinded_sig = blind_sig; break; } case TALER_HELPER_RSA_MT_RES_SIGN_FAILURE: @@ -597,9 +616,9 @@ end: enum TALER_ErrorCode TALER_CRYPTO_helper_rsa_batch_sign ( struct TALER_CRYPTO_RsaDenominationHelper *dh, - const struct TALER_CRYPTO_RsaSignRequest *rsrs, unsigned int rsrs_length, - struct TALER_BlindedDenominationSignature *bss) + const struct TALER_CRYPTO_RsaSignRequest rsrs[static rsrs_length], + struct TALER_BlindedDenominationSignature bss[static rsrs_length]) { enum TALER_ErrorCode ec = TALER_EC_INVALID; unsigned int rpos; @@ -655,9 +674,9 @@ TALER_CRYPTO_helper_rsa_batch_sign ( sr->header.size = htons (sizeof (*sr) + rsr->msg_size); sr->reserved = htonl (0); sr->h_rsa = *rsr->h_rsa; - memcpy (&sr[1], - rsr->msg, - rsr->msg_size); + GNUNET_memcpy (&sr[1], + rsr->msg, + rsr->msg_size); wbuf += sizeof (*sr) + rsr->msg_size; } GNUNET_assert (wbuf == &obuf[mlen]); @@ -750,6 +769,7 @@ more: const struct TALER_CRYPTO_SignResponse *sr = (const struct TALER_CRYPTO_SignResponse *) buf; struct GNUNET_CRYPTO_RsaSignature *rsa_signature; + struct GNUNET_CRYPTO_BlindedSignature *blind_sig; rsa_signature = GNUNET_CRYPTO_rsa_signature_decode ( &sr[1], @@ -763,8 +783,11 @@ more: GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received %u signature\n", wpos); - bss[wpos].cipher = TALER_DENOMINATION_RSA; - bss[wpos].details.blinded_rsa_signature = rsa_signature; + blind_sig = GNUNET_new (struct GNUNET_CRYPTO_BlindedSignature); + blind_sig->cipher = GNUNET_CRYPTO_BSA_RSA; + blind_sig->rc = 1; + blind_sig->details.blinded_rsa_signature = rsa_signature; + bss[wpos].blinded_sig = blind_sig; wpos++; if (wpos == rend) { diff --git a/src/util/currencies.conf b/src/util/currencies.conf new file mode 100644 index 000000000..0fa831bf3 --- /dev/null +++ b/src/util/currencies.conf @@ -0,0 +1,89 @@ +[currency-euro] +ENABLED = YES +name = "Euro" +code = "EUR" +fractional_input_digits = 2 +fractional_normal_digits = 2 +fractional_trailing_zero_digits = 2 +alt_unit_names = {"0":"€"} + +[currency-swiss-francs] +ENABLED = YES +name = "Swiss Francs" +code = "CHF" +fractional_input_digits = 2 +fractional_normal_digits = 2 +fractional_trailing_zero_digits = 2 +alt_unit_names = {"0":"Fr.","-2":"Rp."} + +[currency-forint] +ENABLED = NO +name = "Hungarian Forint" +code = "HUF" +fractional_input_digits = 0 +fractional_normal_digits = 0 +fractional_trailing_zero_digits = 0 +alt_unit_names = {"0":"Ft"} + +[currency-us-dollar] +ENABLED = NO +name = "US Dollar" +code = "USD" +fractional_input_digits = 2 +fractional_normal_digits = 2 +fractional_trailing_zero_digits = 2 +alt_unit_names = {"0":"$"} + +[currency-kudos] +ENABLED = YES +name = "Kudos (Taler Demonstrator)" +code = "KUDOS" +fractional_input_digits = 2 +fractional_normal_digits = 2 +fractional_trailing_zero_digits = 2 +alt_unit_names = {"0":"ク"} + +[currency-testkudos] +ENABLED = YES +name = "Test-kudos (Taler Demonstrator)" +code = "TESTKUDOS" +fractional_input_digits = 2 +fractional_normal_digits = 2 +fractional_trailing_zero_digits = 2 +alt_unit_names = {"0":"テ","3":"kテ","-3":"mテ"} + +[currency-japanese-yen] +ENABLED = NO +name = "Japanese Yen" +code = "JPY" +fractional_input_digits = 2 +fractional_normal_digits = 0 +fractional_trailing_zero_digits = 2 +alt_unit_names = {"0":"¥"} + +[currency-bitcoin-mainnet] +ENABLED = NO +name = "Bitcoin (Mainnet)" +code = "BITCOINBTC" +fractional_input_digits = 8 +fractional_normal_digits = 3 +fractional_trailing_zero_digits = 0 +alt_unit_names = {"0":"BTC","-3":"mBTC"} + +[currency-ethereum] +ENABLED = NO +name = "WAI-ETHER (Ethereum)" +code = "EthereumWAI" +fractional_input_digits = 0 +fractional_normal_digits = 0 +fractional_trailing_zero_digits = 0 +alt_unit_names = {"0":"WAI","3":"KWAI","6":"MWAI","9":"GWAI","12":"Szabo","15":"Finney","18":"Ether","21":"KEther","24":"MEther"} + +[currency-netzbon] +ENABLED=YES +name=NetzBon +code=NETZBON +fractional_input_digits=2 +fractional_normal_digits=2 +fractional_trailing_zero_digits=2 +alt_unit_names = {"0":"NETZBON"} diff --git a/src/util/denom.c b/src/util/denom.c index c1c3cdf5a..cb232c4a3 100644 --- a/src/util/denom.c +++ b/src/util/denom.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2021, 2022 Taler Systems SA + Copyright (C) 2021, 2022, 2023 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 @@ -25,60 +25,27 @@ enum GNUNET_GenericReturnValue TALER_denom_priv_create (struct TALER_DenominationPrivateKey *denom_priv, struct TALER_DenominationPublicKey *denom_pub, - enum TALER_DenominationCipher cipher, + enum GNUNET_CRYPTO_BlindSignatureAlgorithm cipher, ...) { - memset (denom_priv, - 0, - sizeof (*denom_priv)); + enum GNUNET_GenericReturnValue ret; + va_list ap; + memset (denom_pub, 0, sizeof (*denom_pub)); - - switch (cipher) - { - case TALER_DENOMINATION_INVALID: - GNUNET_break (0); - return GNUNET_SYSERR; - case TALER_DENOMINATION_RSA: - { - va_list ap; - unsigned int bits; - - va_start (ap, cipher); - bits = va_arg (ap, unsigned int); - va_end (ap); - if (bits < 512) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - denom_priv->details.rsa_private_key - = GNUNET_CRYPTO_rsa_private_key_create (bits); - } - if (NULL == denom_priv->details.rsa_private_key) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - denom_pub->details.rsa_public_key - = GNUNET_CRYPTO_rsa_private_key_get_public ( - denom_priv->details.rsa_private_key); - denom_priv->cipher = TALER_DENOMINATION_RSA; - denom_pub->cipher = TALER_DENOMINATION_RSA; - return GNUNET_OK; - case TALER_DENOMINATION_CS: - GNUNET_CRYPTO_cs_private_key_generate (&denom_priv->details.cs_private_key); - GNUNET_CRYPTO_cs_private_key_get_public ( - &denom_priv->details.cs_private_key, - &denom_pub->details.cs_public_key); - denom_priv->cipher = TALER_DENOMINATION_CS; - denom_pub->cipher = TALER_DENOMINATION_CS; - return GNUNET_OK; - default: - GNUNET_break (0); - } - return GNUNET_SYSERR; + memset (denom_priv, + 0, + sizeof (*denom_priv)); + va_start (ap, + cipher); + ret = GNUNET_CRYPTO_blind_sign_keys_create_va ( + &denom_priv->bsign_priv_key, + &denom_pub->bsign_pub_key, + cipher, + ap); + va_end (ap); + return ret; } @@ -88,57 +55,13 @@ TALER_denom_sign_blinded (struct TALER_BlindedDenominationSignature *denom_sig, bool for_melt, const struct TALER_BlindedPlanchet *blinded_planchet) { - memset (denom_sig, - 0, - sizeof (*denom_sig)); - if (blinded_planchet->cipher != denom_priv->cipher) - { - GNUNET_break (0); + denom_sig->blinded_sig + = GNUNET_CRYPTO_blind_sign (denom_priv->bsign_priv_key, + for_melt ? "rm" : "rw", + blinded_planchet->blinded_message); + if (NULL == denom_sig->blinded_sig) return GNUNET_SYSERR; - } - switch (denom_priv->cipher) - { - case TALER_DENOMINATION_INVALID: - GNUNET_break (0); - return GNUNET_SYSERR; - case TALER_DENOMINATION_RSA: - denom_sig->details.blinded_rsa_signature - = GNUNET_CRYPTO_rsa_sign_blinded ( - denom_priv->details.rsa_private_key, - blinded_planchet->details.rsa_blinded_planchet.blinded_msg, - blinded_planchet->details.rsa_blinded_planchet.blinded_msg_size); - if (NULL == denom_sig->details.blinded_rsa_signature) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - denom_sig->cipher = TALER_DENOMINATION_RSA; - return GNUNET_OK; - case TALER_DENOMINATION_CS: - { - struct GNUNET_CRYPTO_CsRSecret r[2]; - - GNUNET_CRYPTO_cs_r_derive ( - &blinded_planchet->details.cs_blinded_planchet.nonce.nonce, - for_melt ? "rm" : "rw", - &denom_priv->details.cs_private_key, - r); - denom_sig->details.blinded_cs_answer.b = - GNUNET_CRYPTO_cs_sign_derive (&denom_priv->details.cs_private_key, - r, - blinded_planchet->details. - cs_blinded_planchet.c, - &blinded_planchet->details. - cs_blinded_planchet.nonce.nonce, - &denom_sig->details.blinded_cs_answer. - s_scalar); - denom_sig->cipher = TALER_DENOMINATION_CS; - } - return GNUNET_OK; - default: - GNUNET_break (0); - } - return GNUNET_SYSERR; + return GNUNET_OK; } @@ -146,82 +69,24 @@ enum GNUNET_GenericReturnValue TALER_denom_sig_unblind ( struct TALER_DenominationSignature *denom_sig, const struct TALER_BlindedDenominationSignature *bdenom_sig, - const union TALER_DenominationBlindingKeyP *bks, + const union GNUNET_CRYPTO_BlindingSecretP *bks, const struct TALER_CoinPubHashP *c_hash, const struct TALER_ExchangeWithdrawValues *alg_values, const struct TALER_DenominationPublicKey *denom_pub) { - if (bdenom_sig->cipher != denom_pub->cipher) + denom_sig->unblinded_sig + = GNUNET_CRYPTO_blind_sig_unblind (bdenom_sig->blinded_sig, + bks, + c_hash, + sizeof (*c_hash), + alg_values->blinding_inputs, + denom_pub->bsign_pub_key); + if (NULL == denom_sig->unblinded_sig) { - GNUNET_break (0); + GNUNET_break_op (0); return GNUNET_SYSERR; } - switch (denom_pub->cipher) - { - case TALER_DENOMINATION_INVALID: - GNUNET_break (0); - return GNUNET_SYSERR; - case TALER_DENOMINATION_RSA: - denom_sig->details.rsa_signature - = GNUNET_CRYPTO_rsa_unblind ( - bdenom_sig->details.blinded_rsa_signature, - &bks->rsa_bks, - denom_pub->details.rsa_public_key); - if (NULL == denom_sig->details.rsa_signature) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - denom_sig->cipher = TALER_DENOMINATION_RSA; - return GNUNET_OK; - case TALER_DENOMINATION_CS: - { - struct GNUNET_CRYPTO_CsBlindingSecret bs[2]; - struct GNUNET_CRYPTO_CsC c[2]; - struct TALER_DenominationCSPublicRPairP r_pub_blind; - - GNUNET_CRYPTO_cs_blinding_secrets_derive (&bks->nonce, - bs); - GNUNET_CRYPTO_cs_calc_blinded_c ( - bs, - alg_values->details.cs_values.r_pub, - &denom_pub->details.cs_public_key, - &c_hash->hash, - sizeof(struct GNUNET_HashCode), - c, - r_pub_blind.r_pub); - denom_sig->details.cs_signature.r_point - = r_pub_blind.r_pub[bdenom_sig->details.blinded_cs_answer.b]; - GNUNET_CRYPTO_cs_unblind (&bdenom_sig->details.blinded_cs_answer.s_scalar, - &bs[bdenom_sig->details.blinded_cs_answer.b], - &denom_sig->details.cs_signature.s_scalar); - denom_sig->cipher = TALER_DENOMINATION_CS; - return GNUNET_OK; - } - default: - GNUNET_break (0); - } - return GNUNET_SYSERR; -} - - -void -TALER_rsa_pub_hash (const struct GNUNET_CRYPTO_RsaPublicKey *rsa, - struct TALER_RsaPubHashP *h_rsa) -{ - GNUNET_CRYPTO_rsa_public_key_hash (rsa, - &h_rsa->hash); - -} - - -void -TALER_cs_pub_hash (const struct GNUNET_CRYPTO_CsPublicKey *cs, - struct TALER_CsPubHashP *h_cs) -{ - GNUNET_CRYPTO_hash (cs, - sizeof(*cs), - &h_cs->hash); + return GNUNET_OK; } @@ -229,9 +94,11 @@ void TALER_denom_pub_hash (const struct TALER_DenominationPublicKey *denom_pub, struct TALER_DenominationHashP *denom_hash) { + struct GNUNET_CRYPTO_BlindSignPublicKey *bsp + = denom_pub->bsign_pub_key; uint32_t opt[2] = { htonl (denom_pub->age_mask.bits), - htonl ((uint32_t) denom_pub->cipher) + htonl ((uint32_t) bsp->cipher) }; struct GNUNET_HashContext *hc; @@ -239,15 +106,15 @@ TALER_denom_pub_hash (const struct TALER_DenominationPublicKey *denom_pub, GNUNET_CRYPTO_hash_context_read (hc, opt, sizeof (opt)); - switch (denom_pub->cipher) + switch (bsp->cipher) { - case TALER_DENOMINATION_RSA: + case GNUNET_CRYPTO_BSA_RSA: { void *buf; size_t blen; blen = GNUNET_CRYPTO_rsa_public_key_encode ( - denom_pub->details.rsa_public_key, + bsp->details.rsa_public_key, &buf); GNUNET_CRYPTO_hash_context_read (hc, buf, @@ -255,10 +122,10 @@ TALER_denom_pub_hash (const struct TALER_DenominationPublicKey *denom_pub, GNUNET_free (buf); } break; - case TALER_DENOMINATION_CS: + case GNUNET_CRYPTO_BSA_CS: GNUNET_CRYPTO_hash_context_read (hc, - &denom_pub->details.cs_public_key, - sizeof(denom_pub->details.cs_public_key)); + &bsp->details.cs_public_key, + sizeof(bsp->details.cs_public_key)); break; default: GNUNET_assert (0); @@ -268,37 +135,24 @@ TALER_denom_pub_hash (const struct TALER_DenominationPublicKey *denom_pub, } -void -TALER_denom_priv_to_pub (const struct TALER_DenominationPrivateKey *denom_priv, - const struct TALER_AgeMask age_mask, - struct TALER_DenominationPublicKey *denom_pub) +const struct TALER_ExchangeWithdrawValues * +TALER_denom_ewv_rsa_singleton () { - switch (denom_priv->cipher) - { - case TALER_DENOMINATION_RSA: - denom_pub->cipher = TALER_DENOMINATION_RSA; - denom_pub->age_mask = age_mask; - denom_pub->details.rsa_public_key - = GNUNET_CRYPTO_rsa_private_key_get_public ( - denom_priv->details.rsa_private_key); - return; - case TALER_DENOMINATION_CS: - denom_pub->cipher = TALER_DENOMINATION_CS; - denom_pub->age_mask = age_mask; - GNUNET_CRYPTO_cs_private_key_get_public ( - &denom_priv->details.cs_private_key, - &denom_pub->details.cs_public_key); - return; - default: - GNUNET_assert (0); - } + static struct GNUNET_CRYPTO_BlindingInputValues bi = { + .cipher = GNUNET_CRYPTO_BSA_RSA + }; + static struct TALER_ExchangeWithdrawValues alg_values = { + .blinding_inputs = &bi + }; + return &alg_values; } enum GNUNET_GenericReturnValue TALER_denom_blind ( const struct TALER_DenominationPublicKey *dk, - const union TALER_DenominationBlindingKeyP *coin_bks, + const union GNUNET_CRYPTO_BlindingSecretP *coin_bks, + const union GNUNET_CRYPTO_BlindSessionNonce *nonce, const struct TALER_AgeCommitmentHash *ach, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_ExchangeWithdrawValues *alg_values, @@ -308,44 +162,16 @@ TALER_denom_blind ( TALER_coin_pub_hash (coin_pub, ach, c_hash); - switch (dk->cipher) - { - case TALER_DENOMINATION_RSA: - blinded_planchet->cipher = dk->cipher; - if (GNUNET_YES != - GNUNET_CRYPTO_rsa_blind ( - &c_hash->hash, - &coin_bks->rsa_bks, - dk->details.rsa_public_key, - &blinded_planchet->details.rsa_blinded_planchet.blinded_msg, - &blinded_planchet->details.rsa_blinded_planchet.blinded_msg_size)) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - return GNUNET_OK; - case TALER_DENOMINATION_CS: - { - struct TALER_DenominationCSPublicRPairP blinded_r_pub; - struct GNUNET_CRYPTO_CsBlindingSecret bs[2]; - - blinded_planchet->cipher = TALER_DENOMINATION_CS; - GNUNET_CRYPTO_cs_blinding_secrets_derive (&coin_bks->nonce, - bs); - GNUNET_CRYPTO_cs_calc_blinded_c ( - bs, - alg_values->details.cs_values.r_pub, - &dk->details.cs_public_key, - c_hash, - sizeof(*c_hash), - blinded_planchet->details.cs_blinded_planchet.c, - blinded_r_pub.r_pub); - return GNUNET_OK; - } - default: - GNUNET_break (0); + blinded_planchet->blinded_message + = GNUNET_CRYPTO_message_blind_to_sign (dk->bsign_pub_key, + coin_bks, + nonce, + c_hash, + sizeof (*c_hash), + alg_values->blinding_inputs); + if (NULL == blinded_planchet->blinded_message) return GNUNET_SYSERR; - } + return GNUNET_OK; } @@ -354,64 +180,20 @@ TALER_denom_pub_verify (const struct TALER_DenominationPublicKey *denom_pub, const struct TALER_DenominationSignature *denom_sig, const struct TALER_CoinPubHashP *c_hash) { - if (denom_pub->cipher != denom_sig->cipher) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - switch (denom_pub->cipher) - { - case TALER_DENOMINATION_INVALID: - GNUNET_break (0); - return GNUNET_NO; - case TALER_DENOMINATION_RSA: - if (GNUNET_OK != - GNUNET_CRYPTO_rsa_verify (&c_hash->hash, - denom_sig->details.rsa_signature, - denom_pub->details.rsa_public_key)) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Coin signature is invalid\n"); - return GNUNET_NO; - } - return GNUNET_YES; - case TALER_DENOMINATION_CS: - if (GNUNET_OK != - GNUNET_CRYPTO_cs_verify (&denom_sig->details.cs_signature, - &denom_pub->details.cs_public_key, - &c_hash->hash, - sizeof(struct GNUNET_HashCode))) - { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Coin signature is invalid\n"); - return GNUNET_NO; - } - return GNUNET_YES; - default: - GNUNET_assert (0); - } + return GNUNET_CRYPTO_blind_sig_verify (denom_pub->bsign_pub_key, + denom_sig->unblinded_sig, + c_hash, + sizeof (*c_hash)); } void TALER_denom_pub_free (struct TALER_DenominationPublicKey *denom_pub) { - switch (denom_pub->cipher) + if (NULL != denom_pub->bsign_pub_key) { - case TALER_DENOMINATION_INVALID: - return; - case TALER_DENOMINATION_RSA: - if (NULL != denom_pub->details.rsa_public_key) - { - GNUNET_CRYPTO_rsa_public_key_free (denom_pub->details.rsa_public_key); - denom_pub->details.rsa_public_key = NULL; - } - denom_pub->cipher = TALER_DENOMINATION_INVALID; - return; - case TALER_DENOMINATION_CS: - return; - default: - GNUNET_assert (0); + GNUNET_CRYPTO_blind_sign_pub_decref (denom_pub->bsign_pub_key); + denom_pub->bsign_pub_key = NULL; } } @@ -419,22 +201,10 @@ TALER_denom_pub_free (struct TALER_DenominationPublicKey *denom_pub) void TALER_denom_priv_free (struct TALER_DenominationPrivateKey *denom_priv) { - switch (denom_priv->cipher) + if (NULL != denom_priv->bsign_priv_key) { - case TALER_DENOMINATION_INVALID: - return; - case TALER_DENOMINATION_RSA: - if (NULL != denom_priv->details.rsa_private_key) - { - GNUNET_CRYPTO_rsa_private_key_free (denom_priv->details.rsa_private_key); - denom_priv->details.rsa_private_key = NULL; - } - denom_priv->cipher = TALER_DENOMINATION_INVALID; - return; - case TALER_DENOMINATION_CS: - return; - default: - GNUNET_assert (0); + GNUNET_CRYPTO_blind_sign_priv_decref (denom_priv->bsign_priv_key); + denom_priv->bsign_priv_key = NULL; } } @@ -442,22 +212,10 @@ TALER_denom_priv_free (struct TALER_DenominationPrivateKey *denom_priv) void TALER_denom_sig_free (struct TALER_DenominationSignature *denom_sig) { - switch (denom_sig->cipher) + if (NULL != denom_sig->unblinded_sig) { - case TALER_DENOMINATION_INVALID: - return; - case TALER_DENOMINATION_RSA: - if (NULL != denom_sig->details.rsa_signature) - { - GNUNET_CRYPTO_rsa_signature_free (denom_sig->details.rsa_signature); - denom_sig->details.rsa_signature = NULL; - } - denom_sig->cipher = TALER_DENOMINATION_INVALID; - return; - case TALER_DENOMINATION_CS: - return; - default: - GNUNET_assert (0); + GNUNET_CRYPTO_unblinded_sig_decref (denom_sig->unblinded_sig); + denom_sig->unblinded_sig = NULL; } } @@ -466,89 +224,73 @@ void TALER_blinded_denom_sig_free ( struct TALER_BlindedDenominationSignature *denom_sig) { - switch (denom_sig->cipher) + if (NULL != denom_sig->blinded_sig) { - case TALER_DENOMINATION_INVALID: - return; - case TALER_DENOMINATION_RSA: - if (NULL != denom_sig->details.blinded_rsa_signature) - { - GNUNET_CRYPTO_rsa_signature_free ( - denom_sig->details.blinded_rsa_signature); - denom_sig->details.blinded_rsa_signature = NULL; - } - denom_sig->cipher = TALER_DENOMINATION_INVALID; - return; - case TALER_DENOMINATION_CS: - return; - default: - GNUNET_assert (0); + GNUNET_CRYPTO_blinded_sig_decref (denom_sig->blinded_sig); + denom_sig->blinded_sig = NULL; } } void -TALER_denom_pub_deep_copy (struct TALER_DenominationPublicKey *denom_dst, - const struct TALER_DenominationPublicKey *denom_src) +TALER_denom_ewv_free (struct TALER_ExchangeWithdrawValues *ewv) { - *denom_dst = *denom_src; /* shallow copy */ - switch (denom_src->cipher) - { - case TALER_DENOMINATION_RSA: - denom_dst->details.rsa_public_key - = GNUNET_CRYPTO_rsa_public_key_dup ( - denom_src->details.rsa_public_key); + if (ewv == TALER_denom_ewv_rsa_singleton ()) return; - case TALER_DENOMINATION_CS: + if (ewv->blinding_inputs == + TALER_denom_ewv_rsa_singleton ()->blinding_inputs) + { + ewv->blinding_inputs = NULL; return; - default: - GNUNET_assert (0); + } + if (NULL != ewv->blinding_inputs) + { + GNUNET_CRYPTO_blinding_input_values_decref (ewv->blinding_inputs); + ewv->blinding_inputs = NULL; } } void -TALER_denom_sig_deep_copy (struct TALER_DenominationSignature *denom_dst, - const struct TALER_DenominationSignature *denom_src) +TALER_denom_ewv_copy (struct TALER_ExchangeWithdrawValues *bi_dst, + const struct TALER_ExchangeWithdrawValues *bi_src) { - *denom_dst = *denom_src; /* shallow copy */ - switch (denom_src->cipher) + if (bi_src == TALER_denom_ewv_rsa_singleton ()) { - case TALER_DENOMINATION_INVALID: - return; - case TALER_DENOMINATION_RSA: - denom_dst->details.rsa_signature - = GNUNET_CRYPTO_rsa_signature_dup ( - denom_src->details.rsa_signature); - return; - case TALER_DENOMINATION_CS: + *bi_dst = *bi_src; return; - default: - GNUNET_assert (0); } + bi_dst->blinding_inputs + = GNUNET_CRYPTO_blinding_input_values_incref (bi_src->blinding_inputs); +} + + +void +TALER_denom_pub_copy (struct TALER_DenominationPublicKey *denom_dst, + const struct TALER_DenominationPublicKey *denom_src) +{ + denom_dst->age_mask = denom_src->age_mask; + denom_dst->bsign_pub_key + = GNUNET_CRYPTO_bsign_pub_incref (denom_src->bsign_pub_key); } void -TALER_blinded_denom_sig_deep_copy ( +TALER_denom_sig_copy (struct TALER_DenominationSignature *denom_dst, + const struct TALER_DenominationSignature *denom_src) +{ + denom_dst->unblinded_sig + = GNUNET_CRYPTO_ub_sig_incref (denom_src->unblinded_sig); +} + + +void +TALER_blinded_denom_sig_copy ( struct TALER_BlindedDenominationSignature *denom_dst, const struct TALER_BlindedDenominationSignature *denom_src) { - *denom_dst = *denom_src; /* shallow copy */ - switch (denom_src->cipher) - { - case TALER_DENOMINATION_INVALID: - return; - case TALER_DENOMINATION_RSA: - denom_dst->details.blinded_rsa_signature - = GNUNET_CRYPTO_rsa_signature_dup ( - denom_src->details.blinded_rsa_signature); - return; - case TALER_DENOMINATION_CS: - return; - default: - GNUNET_assert (0); - } + denom_dst->blinded_sig + = GNUNET_CRYPTO_blind_sig_incref (denom_src->blinded_sig); } @@ -556,24 +298,14 @@ int TALER_denom_pub_cmp (const struct TALER_DenominationPublicKey *denom1, const struct TALER_DenominationPublicKey *denom2) { - if (denom1->cipher != denom2->cipher) - return (denom1->cipher > denom2->cipher) ? 1 : -1; + if (denom1->bsign_pub_key->cipher != + denom2->bsign_pub_key->cipher) + return (denom1->bsign_pub_key->cipher > + denom2->bsign_pub_key->cipher) ? 1 : -1; if (denom1->age_mask.bits != denom2->age_mask.bits) return (denom1->age_mask.bits > denom2->age_mask.bits) ? 1 : -1; - switch (denom1->cipher) - { - case TALER_DENOMINATION_INVALID: - return 0; - case TALER_DENOMINATION_RSA: - return GNUNET_CRYPTO_rsa_public_key_cmp (denom1->details.rsa_public_key, - denom2->details.rsa_public_key); - case TALER_DENOMINATION_CS: - return GNUNET_memcmp (&denom1->details.cs_public_key, - &denom2->details.cs_public_key); - default: - GNUNET_assert (0); - } - return -2; + return GNUNET_CRYPTO_bsign_pub_cmp (denom1->bsign_pub_key, + denom2->bsign_pub_key); } @@ -581,22 +313,8 @@ int TALER_denom_sig_cmp (const struct TALER_DenominationSignature *sig1, const struct TALER_DenominationSignature *sig2) { - if (sig1->cipher != sig2->cipher) - return (sig1->cipher > sig2->cipher) ? 1 : -1; - switch (sig1->cipher) - { - case TALER_DENOMINATION_INVALID: - return 0; - case TALER_DENOMINATION_RSA: - return GNUNET_CRYPTO_rsa_signature_cmp (sig1->details.rsa_signature, - sig2->details.rsa_signature); - case TALER_DENOMINATION_CS: - return GNUNET_memcmp (&sig1->details.cs_signature, - &sig2->details.cs_signature); - default: - GNUNET_assert (0); - } - return -2; + return GNUNET_CRYPTO_ub_sig_cmp (sig1->unblinded_sig, + sig1->unblinded_sig); } @@ -605,27 +323,8 @@ TALER_blinded_planchet_cmp ( const struct TALER_BlindedPlanchet *bp1, const struct TALER_BlindedPlanchet *bp2) { - if (bp1->cipher != bp2->cipher) - return (bp1->cipher > bp2->cipher) ? 1 : -1; - switch (bp1->cipher) - { - case TALER_DENOMINATION_INVALID: - return 0; - case TALER_DENOMINATION_RSA: - if (bp1->details.rsa_blinded_planchet.blinded_msg_size != - bp2->details.rsa_blinded_planchet.blinded_msg_size) - return (bp1->details.rsa_blinded_planchet.blinded_msg_size > - bp2->details.rsa_blinded_planchet.blinded_msg_size) ? 1 : -1; - return memcmp (bp1->details.rsa_blinded_planchet.blinded_msg, - bp2->details.rsa_blinded_planchet.blinded_msg, - bp1->details.rsa_blinded_planchet.blinded_msg_size); - case TALER_DENOMINATION_CS: - return GNUNET_memcmp (&bp1->details.cs_blinded_planchet, - &bp2->details.cs_blinded_planchet); - default: - GNUNET_assert (0); - } - return -2; + return GNUNET_CRYPTO_blinded_message_cmp (bp1->blinded_message, + bp2->blinded_message); } @@ -634,22 +333,8 @@ TALER_blinded_denom_sig_cmp ( const struct TALER_BlindedDenominationSignature *sig1, const struct TALER_BlindedDenominationSignature *sig2) { - if (sig1->cipher != sig2->cipher) - return (sig1->cipher > sig2->cipher) ? 1 : -1; - switch (sig1->cipher) - { - case TALER_DENOMINATION_INVALID: - return 0; - case TALER_DENOMINATION_RSA: - return GNUNET_CRYPTO_rsa_signature_cmp (sig1->details.blinded_rsa_signature, - sig2->details.blinded_rsa_signature); - case TALER_DENOMINATION_CS: - return GNUNET_memcmp (&sig1->details.blinded_cs_answer, - &sig2->details.blinded_cs_answer); - default: - GNUNET_assert (0); - } - return -2; + return GNUNET_CRYPTO_blind_sig_cmp (sig1->blinded_sig, + sig1->blinded_sig); } @@ -657,31 +342,31 @@ void TALER_blinded_planchet_hash_ (const struct TALER_BlindedPlanchet *bp, struct GNUNET_HashContext *hash_context) { - uint32_t cipher = htonl (bp->cipher); + const struct GNUNET_CRYPTO_BlindedMessage *bm = bp->blinded_message; + uint32_t cipher = htonl (bm->cipher); GNUNET_CRYPTO_hash_context_read (hash_context, &cipher, sizeof (cipher)); - switch (bp->cipher) + switch (bm->cipher) { - case TALER_DENOMINATION_INVALID: - break; - case TALER_DENOMINATION_RSA: + case GNUNET_CRYPTO_BSA_INVALID: + GNUNET_break (0); + return; + case GNUNET_CRYPTO_BSA_RSA: GNUNET_CRYPTO_hash_context_read ( hash_context, - bp->details.rsa_blinded_planchet.blinded_msg, - bp->details.rsa_blinded_planchet.blinded_msg_size); - break; - case TALER_DENOMINATION_CS: + bm->details.rsa_blinded_message.blinded_msg, + bm->details.rsa_blinded_message.blinded_msg_size); + return; + case GNUNET_CRYPTO_BSA_CS: GNUNET_CRYPTO_hash_context_read ( hash_context, - &bp->details.cs_blinded_planchet, - sizeof (bp->details.cs_blinded_planchet)); - break; - default: - GNUNET_assert (0); - break; + &bm->details.cs_blinded_message, + sizeof (bm->details.cs_blinded_message)); + return; } + GNUNET_assert (0); } @@ -689,14 +374,17 @@ void TALER_planchet_blinding_secret_create ( const struct TALER_PlanchetMasterSecretP *ps, const struct TALER_ExchangeWithdrawValues *alg_values, - union TALER_DenominationBlindingKeyP *bks) + union GNUNET_CRYPTO_BlindingSecretP *bks) { - switch (alg_values->cipher) + const struct GNUNET_CRYPTO_BlindingInputValues *bi = + alg_values->blinding_inputs; + + switch (bi->cipher) { - case TALER_DENOMINATION_INVALID: + case GNUNET_CRYPTO_BSA_INVALID: GNUNET_break (0); return; - case TALER_DENOMINATION_RSA: + case GNUNET_CRYPTO_BSA_RSA: GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_kdf (&bks->rsa_bks, sizeof (bks->rsa_bks), @@ -707,7 +395,7 @@ TALER_planchet_blinding_secret_create ( NULL, 0)); return; - case TALER_DENOMINATION_CS: + case GNUNET_CRYPTO_BSA_CS: GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_kdf (&bks->nonce, sizeof (bks->nonce), @@ -715,14 +403,13 @@ TALER_planchet_blinding_secret_create ( strlen ("bseed"), ps, sizeof(*ps), - &alg_values->details.cs_values, - sizeof(alg_values->details.cs_values), + &bi->details.cs_values, + sizeof(bi->details.cs_values), NULL, 0)); return; - default: - GNUNET_break (0); } + GNUNET_assert (0); } @@ -732,9 +419,18 @@ TALER_planchet_setup_coin_priv ( const struct TALER_ExchangeWithdrawValues *alg_values, struct TALER_CoinSpendPrivateKeyP *coin_priv) { - switch (alg_values->cipher) + const struct GNUNET_CRYPTO_BlindingInputValues *bi + = alg_values->blinding_inputs; + + switch (bi->cipher) { - case TALER_DENOMINATION_RSA: + case GNUNET_CRYPTO_BSA_INVALID: + GNUNET_break (0); + memset (coin_priv, + 0, + sizeof (*coin_priv)); + return; + case GNUNET_CRYPTO_BSA_RSA: GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_kdf (coin_priv, sizeof (*coin_priv), @@ -744,8 +440,8 @@ TALER_planchet_setup_coin_priv ( sizeof(*ps), NULL, 0)); - break; - case TALER_DENOMINATION_CS: + return; + case GNUNET_CRYPTO_BSA_CS: GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_kdf (coin_priv, sizeof (*coin_priv), @@ -753,37 +449,24 @@ TALER_planchet_setup_coin_priv ( strlen ("coin"), ps, sizeof(*ps), - &alg_values->details.cs_values, - sizeof(alg_values->details.cs_values), + &bi->details.cs_values, + sizeof(bi->details.cs_values), NULL, 0)); - break; - default: - GNUNET_break (0); return; } + GNUNET_assert (0); } void TALER_blinded_planchet_free (struct TALER_BlindedPlanchet *blinded_planchet) { - switch (blinded_planchet->cipher) + if (NULL != blinded_planchet->blinded_message) { - case TALER_DENOMINATION_INVALID: - GNUNET_break (0); - return; - case TALER_DENOMINATION_RSA: - GNUNET_free (blinded_planchet->details.rsa_blinded_planchet.blinded_msg); - return; - case TALER_DENOMINATION_CS: - memset (blinded_planchet, - 0, - sizeof (*blinded_planchet)); - /* nothing to do for CS */ - return; + GNUNET_CRYPTO_blinded_message_decref (blinded_planchet->blinded_message); + blinded_planchet->blinded_message = NULL; } - GNUNET_assert (0); } diff --git a/src/util/exchange_signatures.c b/src/util/exchange_signatures.c index d8bf716c7..aaefb5cec 100644 --- a/src/util/exchange_signatures.c +++ b/src/util/exchange_signatures.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2021, 2022 Taler Systems SA + Copyright (C) 2021-2023 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 @@ -78,12 +78,12 @@ struct TALER_DepositConfirmationPS * Amount to be deposited, excluding fee. Calculated from the * amount with fee and the fee from the deposit request. */ - struct TALER_AmountNBO amount_without_fee; + struct TALER_AmountNBO total_without_fee; /** - * The public key of the coin that was deposited. + * Hash over all of the coin signatures. */ - struct TALER_CoinSpendPublicKeyP coin_pub; + struct GNUNET_HashCode h_coin_sigs; /** * The Merchant's public key. Allows the merchant to later refund @@ -105,8 +105,9 @@ TALER_exchange_online_deposit_confirmation_sign ( struct GNUNET_TIME_Timestamp exchange_timestamp, struct GNUNET_TIME_Timestamp wire_deadline, struct GNUNET_TIME_Timestamp refund_deadline, - const struct TALER_Amount *amount_without_fee, - const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_Amount *total_without_fee, + unsigned int num_coins, + const struct TALER_CoinSpendSignatureP *coin_sigs[static num_coins], const struct TALER_MerchantPublicKeyP *merchant_pub, struct TALER_ExchangePublicKeyP *pub, struct TALER_ExchangeSignatureP *sig) @@ -119,14 +120,22 @@ TALER_exchange_online_deposit_confirmation_sign ( .exchange_timestamp = GNUNET_TIME_timestamp_hton (exchange_timestamp), .wire_deadline = GNUNET_TIME_timestamp_hton (wire_deadline), .refund_deadline = GNUNET_TIME_timestamp_hton (refund_deadline), - .coin_pub = *coin_pub, - .merchant_pub = *merchant_pub + .merchant_pub = *merchant_pub, + .h_policy = {{{0}}} }; - + struct GNUNET_HashContext *hc; + + hc = GNUNET_CRYPTO_hash_context_start (); + for (unsigned int i = 0; i<num_coins; i++) + GNUNET_CRYPTO_hash_context_read (hc, + coin_sigs[i], + sizeof (*coin_sigs[i])); + GNUNET_CRYPTO_hash_context_finish (hc, + &dcs.h_coin_sigs); if (NULL != h_policy) dcs.h_policy = *h_policy; - TALER_amount_hton (&dcs.amount_without_fee, - amount_without_fee); + TALER_amount_hton (&dcs.total_without_fee, + total_without_fee); return scb (&dcs.purpose, pub, sig); @@ -141,8 +150,9 @@ TALER_exchange_online_deposit_confirmation_verify ( struct GNUNET_TIME_Timestamp exchange_timestamp, struct GNUNET_TIME_Timestamp wire_deadline, struct GNUNET_TIME_Timestamp refund_deadline, - const struct TALER_Amount *amount_without_fee, - const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_Amount *total_without_fee, + unsigned int num_coins, + const struct TALER_CoinSpendSignatureP *coin_sigs[static num_coins], const struct TALER_MerchantPublicKeyP *merchant_pub, const struct TALER_ExchangePublicKeyP *exchange_pub, const struct TALER_ExchangeSignatureP *exchange_sig) @@ -155,14 +165,21 @@ TALER_exchange_online_deposit_confirmation_verify ( .exchange_timestamp = GNUNET_TIME_timestamp_hton (exchange_timestamp), .wire_deadline = GNUNET_TIME_timestamp_hton (wire_deadline), .refund_deadline = GNUNET_TIME_timestamp_hton (refund_deadline), - .coin_pub = *coin_pub, .merchant_pub = *merchant_pub }; - + struct GNUNET_HashContext *hc; + + hc = GNUNET_CRYPTO_hash_context_start (); + for (unsigned int i = 0; i<num_coins; i++) + GNUNET_CRYPTO_hash_context_read (hc, + coin_sigs[i], + sizeof (*coin_sigs[i])); + GNUNET_CRYPTO_hash_context_finish (hc, + &dcs.h_coin_sigs); if (NULL != h_policy) dcs.h_policy = *h_policy; - TALER_amount_hton (&dcs.amount_without_fee, - amount_without_fee); + TALER_amount_hton (&dcs.total_without_fee, + total_without_fee); if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_DEPOSIT, &dcs, @@ -413,6 +430,34 @@ TALER_exchange_online_age_withdraw_confirmation_sign ( } +enum GNUNET_GenericReturnValue +TALER_exchange_online_age_withdraw_confirmation_verify ( + const struct TALER_AgeWithdrawCommitmentHashP *h_commitment, + uint32_t noreveal_index, + const struct TALER_ExchangePublicKeyP *exchange_pub, + const struct TALER_ExchangeSignatureP *exchange_sig) +{ + struct TALER_AgeWithdrawConfirmationPS confirm = { + .purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_AGE_WITHDRAW), + .purpose.size = htonl (sizeof (confirm)), + .h_commitment = *h_commitment, + .noreveal_index = htonl (noreveal_index) + }; + + if (GNUNET_OK != + GNUNET_CRYPTO_eddsa_verify ( + TALER_SIGNATURE_EXCHANGE_CONFIRM_AGE_WITHDRAW, + &confirm, + &exchange_sig->eddsa_signature, + &exchange_pub->eddsa_pub)) + { + GNUNET_break_op (0); + return GNUNET_SYSERR; + } + return GNUNET_OK; +} + + /* TODO:oec: add signature for age-withdraw, age-reveal */ @@ -1177,10 +1222,10 @@ TALER_exchange_online_denomination_expired_sign ( }; /* strncpy would create a compiler warning */ - memcpy (dua.operation, - op, - GNUNET_MIN (sizeof (dua.operation), - strlen (op))); + GNUNET_memcpy (dua.operation, + op, + GNUNET_MIN (sizeof (dua.operation), + strlen (op))); return scb (&dua.purpose, pub, sig); @@ -1204,10 +1249,10 @@ TALER_exchange_online_denomination_expired_verify ( }; /* strncpy would create a compiler warning */ - memcpy (dua.operation, - op, - GNUNET_MIN (sizeof (dua.operation), - strlen (op))); + GNUNET_memcpy (dua.operation, + op, + GNUNET_MIN (sizeof (dua.operation), + strlen (op))); return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_EXPIRED, &dua, diff --git a/src/util/iban.c b/src/util/iban.c index efd8c4282..c2274d3cb 100644 --- a/src/util/iban.c +++ b/src/util/iban.c @@ -233,9 +233,9 @@ TALER_iban_validate (const char *iban) return GNUNET_strdup ("IBAN number too short to be valid"); if (len > 34) return GNUNET_strdup ("IBAN number too long to be valid"); - memcpy (cc, iban, 2); - memcpy (ibancpy, iban + 4, len - 4); - memcpy (ibancpy + len - 4, iban, 4); + GNUNET_memcpy (cc, iban, 2); + GNUNET_memcpy (ibancpy, iban + 4, len - 4); + GNUNET_memcpy (ibancpy + len - 4, iban, 4); ibancpy[len] = '\0'; cc_entry.code = cc; cc_entry.english = NULL; diff --git a/src/util/merchant_signatures.c b/src/util/merchant_signatures.c index 36f96499c..35e0b0e07 100644 --- a/src/util/merchant_signatures.c +++ b/src/util/merchant_signatures.c @@ -277,7 +277,7 @@ void TALER_merchant_pay_sign ( const struct TALER_PrivateContractHashP *h_contract_terms, const struct TALER_MerchantPrivateKeyP *merch_priv, - struct GNUNET_CRYPTO_EddsaSignature *merch_sig) + struct TALER_MerchantSignatureP *merch_sig) { struct TALER_PaymentResponsePS mr = { .purpose.purpose = htonl (TALER_SIGNATURE_MERCHANT_PAYMENT_OK), @@ -287,7 +287,7 @@ TALER_merchant_pay_sign ( GNUNET_CRYPTO_eddsa_sign (&merch_priv->eddsa_priv, &mr, - merch_sig); + &merch_sig->eddsa_sig); } diff --git a/src/util/offline_signatures.c b/src/util/offline_signatures.c index b1e3b93a3..fbff850df 100644 --- a/src/util/offline_signatures.c +++ b/src/util/offline_signatures.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2020-2022 Taler Systems SA + Copyright (C) 2020-2023 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 @@ -677,6 +677,22 @@ struct TALER_MasterAddWirePS * Hash over the exchange's payto URI. */ struct TALER_PaytoHashP h_payto GNUNET_PACKED; + + /** + * Hash over the conversion URL, all zeros if there + * is no conversion URL. + */ + struct GNUNET_HashCode h_conversion_url; + + /** + * Hash over the debit restrictions. + */ + struct GNUNET_HashCode h_debit_restrictions; + + /** + * Hash over the credit restrictions. + */ + struct GNUNET_HashCode h_credit_restrictions; }; GNUNET_NETWORK_STRUCT_END @@ -685,6 +701,9 @@ GNUNET_NETWORK_STRUCT_END void TALER_exchange_offline_wire_add_sign ( const char *payto_uri, + const char *conversion_url, + const json_t *debit_restrictions, + const json_t *credit_restrictions, struct GNUNET_TIME_Timestamp now, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) @@ -697,6 +716,14 @@ TALER_exchange_offline_wire_add_sign ( TALER_payto_hash (payto_uri, &kv.h_payto); + if (NULL != conversion_url) + GNUNET_CRYPTO_hash (conversion_url, + strlen (conversion_url) + 1, + &kv.h_conversion_url); + TALER_json_hash (debit_restrictions, + &kv.h_debit_restrictions); + TALER_json_hash (credit_restrictions, + &kv.h_credit_restrictions); GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &kv, &master_sig->eddsa_signature); @@ -706,6 +733,9 @@ TALER_exchange_offline_wire_add_sign ( enum GNUNET_GenericReturnValue TALER_exchange_offline_wire_add_verify ( const char *payto_uri, + const char *conversion_url, + const json_t *debit_restrictions, + const json_t *credit_restrictions, struct GNUNET_TIME_Timestamp sign_time, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig) @@ -718,6 +748,14 @@ TALER_exchange_offline_wire_add_verify ( TALER_payto_hash (payto_uri, &aw.h_payto); + if (NULL != conversion_url) + GNUNET_CRYPTO_hash (conversion_url, + strlen (conversion_url) + 1, + &aw.h_conversion_url); + TALER_json_hash (debit_restrictions, + &aw.h_debit_restrictions); + TALER_json_hash (credit_restrictions, + &aw.h_credit_restrictions); return GNUNET_CRYPTO_eddsa_verify ( TALER_SIGNATURE_MASTER_ADD_WIRE, @@ -967,9 +1005,9 @@ TALER_exchange_offline_global_fee_sign ( const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) { - struct TALER_MasterGlobalFeePS kv = { + struct TALER_MasterGlobalFeePS wf = { .purpose.purpose = htonl (TALER_SIGNATURE_MASTER_GLOBAL_FEES), - .purpose.size = htonl (sizeof (kv)), + .purpose.size = htonl (sizeof (wf)), .start_date = GNUNET_TIME_timestamp_hton (start_time), .end_date = GNUNET_TIME_timestamp_hton (end_time), .purse_timeout = GNUNET_TIME_relative_hton (purse_timeout), @@ -977,10 +1015,10 @@ TALER_exchange_offline_global_fee_sign ( .purse_account_limit = htonl (purse_account_limit) }; - TALER_global_fee_set_hton (&kv.fees, + TALER_global_fee_set_hton (&wf.fees, fees); GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, - &kv, + &wf, &master_sig->eddsa_signature); } @@ -1095,6 +1133,22 @@ struct TALER_MasterWireDetailsPS */ struct TALER_PaytoHashP h_wire_details GNUNET_PACKED; + /** + * Hash over the conversion URL, all zeros if there + * is no conversion URL. + */ + struct GNUNET_HashCode h_conversion_url; + + /** + * Hash over the debit restrictions. + */ + struct GNUNET_HashCode h_debit_restrictions; + + /** + * Hash over the credit restrictions. + */ + struct GNUNET_HashCode h_credit_restrictions; + }; GNUNET_NETWORK_STRUCT_END @@ -1103,6 +1157,9 @@ GNUNET_NETWORK_STRUCT_END enum GNUNET_GenericReturnValue TALER_exchange_wire_signature_check ( const char *payto_uri, + const char *conversion_url, + const json_t *debit_restrictions, + const json_t *credit_restrictions, const struct TALER_MasterPublicKeyP *master_pub, const struct TALER_MasterSignatureP *master_sig) { @@ -1113,6 +1170,14 @@ TALER_exchange_wire_signature_check ( TALER_payto_hash (payto_uri, &wd.h_wire_details); + if (NULL != conversion_url) + GNUNET_CRYPTO_hash (conversion_url, + strlen (conversion_url) + 1, + &wd.h_conversion_url); + TALER_json_hash (debit_restrictions, + &wd.h_debit_restrictions); + TALER_json_hash (credit_restrictions, + &wd.h_credit_restrictions); return GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_WIRE_DETAILS, &wd, &master_sig->eddsa_signature, @@ -1123,6 +1188,9 @@ TALER_exchange_wire_signature_check ( void TALER_exchange_wire_signature_make ( const char *payto_uri, + const char *conversion_url, + const json_t *debit_restrictions, + const json_t *credit_restrictions, const struct TALER_MasterPrivateKeyP *master_priv, struct TALER_MasterSignatureP *master_sig) { @@ -1133,6 +1201,14 @@ TALER_exchange_wire_signature_make ( TALER_payto_hash (payto_uri, &wd.h_wire_details); + if (NULL != conversion_url) + GNUNET_CRYPTO_hash (conversion_url, + strlen (conversion_url) + 1, + &wd.h_conversion_url); + TALER_json_hash (debit_restrictions, + &wd.h_debit_restrictions); + TALER_json_hash (credit_restrictions, + &wd.h_credit_restrictions); GNUNET_CRYPTO_eddsa_sign (&master_priv->eddsa_priv, &wd, &master_sig->eddsa_signature); diff --git a/src/util/paths.conf b/src/util/paths.conf index c1d2194d8..f34ccb41e 100644 --- a/src/util/paths.conf +++ b/src/util/paths.conf @@ -17,13 +17,13 @@ TALER_HOME = ${TALER_TEST_HOME:-${HOME:-${USERPROFILE}}} # for how these should be used. # Persistent data storage -TALER_DATA_HOME = ${XDG_DATA_HOME:-$TALER_HOME/.local/share}/taler/ +TALER_DATA_HOME = ${XDG_DATA_HOME:-${TALER_HOME}/.local/share}/taler/ # Configuration files -TALER_CONFIG_HOME = ${XDG_CONFIG_HOME:-$TALER_HOME/.config}/taler/ +TALER_CONFIG_HOME = ${XDG_CONFIG_HOME:-${TALER_HOME}/.config}/taler/ # Cached data, no big deal if lost -TALER_CACHE_HOME = ${XDG_CACHE_HOME:-$TALER_HOME/.cache}/taler/ +TALER_CACHE_HOME = ${XDG_CACHE_HOME:-${TALER_HOME}/.cache}/taler/ # Runtime data (always lost on system boot) TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/taler-system-runtime/ diff --git a/src/util/payto.c b/src/util/payto.c index 81664b1df..6092b73fd 100644 --- a/src/util/payto.c +++ b/src/util/payto.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2019-2022 Taler Systems SA + Copyright (C) 2019-2024 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 @@ -101,7 +101,9 @@ TALER_payto_get_method (const char *payto_uri) char * TALER_xtalerbank_account_from_payto (const char *payto) { + const char *host; const char *beg; + const char *nxt; const char *end; if (0 != strncasecmp (payto, @@ -111,23 +113,27 @@ TALER_xtalerbank_account_from_payto (const char *payto) GNUNET_break_op (0); return NULL; } - beg = strchr (&payto[strlen (PAYTO "x-taler-bank/")], + host = &payto[strlen (PAYTO "x-taler-bank/")]; + beg = strchr (host, '/'); if (NULL == beg) { GNUNET_break_op (0); return NULL; } - beg++; /* now points to $ACCOUNT */ + beg++; /* now points to $ACCOUNT or $PATH */ + nxt = strchr (beg, + '/'); end = strchr (beg, '?'); if (NULL == end) + end = &beg[strlen (beg)]; + while ( (NULL != nxt) && + (end - nxt > 0) ) { - GNUNET_log (GNUNET_ERROR_TYPE_WARNING, - "Invalid payto URI `%s'\n", - payto); - GNUNET_break_op (0); - return GNUNET_strdup (beg); /* optional part is missing */ + beg = nxt + 1; + nxt = strchr (beg, + '/'); } return GNUNET_strndup (beg, end - beg); @@ -155,7 +161,6 @@ validate_payto_iban (const char *account_url) IBAN_PREFIX, strlen (IBAN_PREFIX))) return NULL; /* not an IBAN */ - iban = strrchr (account_url, '/') + 1; #undef IBAN_PREFIX q = strchr (iban, @@ -189,6 +194,138 @@ validate_payto_iban (const char *account_url) } +/** + * Validate payto://x-taler-bank/ account URL (only account information, + * wire subject and amount are ignored). + * + * @param account_url payto URL to parse + * @return NULL on success, otherwise an error message + * to be freed by the caller + */ +static char * +validate_payto_xtalerbank (const char *account_url) +{ + const char *user; + const char *nxt; + const char *beg; + const char *end; + const char *host; + bool dot_ok; + bool post_colon; + bool port_ok; + +#define XTALERBANK_PREFIX PAYTO "x-taler-bank/" + if (0 != strncasecmp (account_url, + XTALERBANK_PREFIX, + strlen (XTALERBANK_PREFIX))) + return NULL; /* not an IBAN */ + host = &account_url[strlen (XTALERBANK_PREFIX)]; +#undef XTALERBANK_PREFIX + beg = strchr (host, + '/'); + if (NULL == beg) + { + return GNUNET_strdup ("account name missing"); + } + beg++; /* now points to $ACCOUNT or $PATH */ + nxt = strchr (beg, + '/'); + end = strchr (beg, + '?'); + if (NULL == end) + { + return GNUNET_strdup ("'receiver-name' parameter missing"); + } + while ( (NULL != nxt) && + (end - nxt > 0) ) + { + beg = nxt + 1; + nxt = strchr (beg, + '/'); + } + user = beg; + if (user == host + 1) + { + return GNUNET_strdup ("domain name missing"); + } + if ('-' == host[0]) + return GNUNET_strdup ("invalid character '-' at start of domain name"); + dot_ok = false; + post_colon = false; + port_ok = false; + while (host != user) + { + char c = host[0]; + + if ('/' == c) + { + /* path started, do not care about characters + in the path */ + break; + } + if (':' == c) + { + post_colon = true; + host++; + continue; + } + if (post_colon) + { + if (! ( ('0' <= c) && ('9' >= c) ) ) + { + char *err; + + GNUNET_asprintf (&err, + "invalid character '%c' in port", + c); + return err; + } + port_ok = true; + } + else + { + if ('.' == c) + { + if (! dot_ok) + return GNUNET_strdup ("invalid domain name (misplaced '.')"); + dot_ok = false; + } + else + { + if (! ( ('-' == c) || + ( ('0' <= c) && ('9' >= c) ) || + ( ('a' <= c) && ('z' >= c) ) || + ( ('A' <= c) && ('Z' >= c) ) ) ) + { + char *err; + + GNUNET_asprintf (&err, + "invalid character '%c' in domain name", + c); + return err; + } + dot_ok = true; + } + } + host++; + } + if (post_colon && (! port_ok) ) + { + return GNUNET_strdup ("port missing after ':'"); + } + { + char *target; + + target = payto_get_key (account_url, + "receiver-name="); + if (NULL == target) + return GNUNET_strdup ("'receiver-name' parameter missing"); + GNUNET_free (target); + } + return NULL; +} + + char * TALER_payto_validate (const char *payto_uri) { @@ -205,7 +342,7 @@ TALER_payto_validate (const char *payto_uri) /* This is more strict than RFC 8905, alas we do not need to support messages/instructions/etc., and it is generally better to start with a narrow whitelist; we can be more permissive later ...*/ #define ALLOWED_CHARACTERS \ - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/:&?-.,=+" + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/:&?-.,=+%~" if (NULL == strchr (ALLOWED_CHARACTERS, (int) payto_uri[i])) { @@ -229,6 +366,8 @@ TALER_payto_validate (const char *payto_uri) if (NULL != (ret = validate_payto_iban (payto_uri))) return ret; /* got a definitive answer */ + if (NULL != (ret = validate_payto_xtalerbank (payto_uri))) + return ret; /* got a definitive answer */ /* Insert other bank account validation methods here later! */ @@ -256,6 +395,242 @@ TALER_payto_get_receiver_name (const char *payto) } +/** + * Normalize "payto://x-taler-bank/$HOSTNAME/[$PATH/]$USERNAME" + * URI in @a input. + * + * Converts to lower-case, except for [$PATH/]$USERNAME which + * is case-sensitive. + * + * @param len number of bytes in @a input + * @param input input URL + * @return NULL on error, otherwise 0-terminated canonicalized URI. + */ +static char * +normalize_payto_x_taler_bank (size_t len, + const char input[static len]) +{ + char *res = GNUNET_malloc (len + 1); + unsigned int sc = 0; + + for (unsigned int i = 0; i<len; i++) + { + char c = input[i]; + + if ('/' == c) + sc++; + if (sc < 4) + res[i] = (char) tolower ((int) c); + else + res[i] = c; + } + return res; +} + + +/** + * Normalize "payto://iban[/$BIC]/$IBAN" + * URI in @a input. + * + * Removes $BIC (if present) and converts $IBAN to upper-case and prefix to + * lower-case. + * + * @param len number of bytes in @a input + * @param input input URL + * @return NULL on error, otherwise 0-terminated canonicalized URI. + */ +static char * +normalize_payto_iban (size_t len, + const char input[static len]) +{ + char *res; + size_t pos = 0; + unsigned int sc = 0; + bool have_bic; + + for (unsigned int i = 0; i<len; i++) + if ('/' == input[i]) + sc++; + if ( (sc > 4) || + (sc < 3) ) + { + GNUNET_break (0); + return NULL; + } + have_bic = (4 == sc); + res = GNUNET_malloc (len + 1); + sc = 0; + for (unsigned int i = 0; i<len; i++) + { + char c = input[i]; + + if ('/' == c) + sc++; + switch (sc) + { + case 0: /* payto: */ + case 1: /* / */ + case 2: /* /iban */ + res[pos++] = (char) tolower ((int) c); + break; + case 3: /* /$BIC or /$IBAN */ + if (have_bic) + continue; + res[pos++] = (char) toupper ((int) c); + break; + case 4: /* /$IBAN */ + res[pos++] = (char) toupper ((int) c); + break; + } + } + GNUNET_assert (pos <= len); + return res; +} + + +/** + * Normalize "payto://upi/$EMAIL" + * URI in @a input. + * + * Converts to lower-case. + * + * @param len number of bytes in @a input + * @param input input URL + * @return NULL on error, otherwise 0-terminated canonicalized URI. + */ +static char * +normalize_payto_upi (size_t len, + const char input[static len]) +{ + char *res = GNUNET_malloc (len + 1); + + for (unsigned int i = 0; i<len; i++) + { + char c = input[i]; + + res[i] = (char) tolower ((int) c); + } + return res; +} + + +/** + * Normalize "payto://bitcoin/$ADDRESS" + * URI in @a input. + * + * Converts to lower-case, except for $ADDRESS which + * is case-sensitive. + * + * @param len number of bytes in @a input + * @param input input URL + * @return NULL on error, otherwise 0-terminated canonicalized URI. + */ +static char * +normalize_payto_bitcoin (size_t len, + const char input[static len]) +{ + char *res = GNUNET_malloc (len + 1); + unsigned int sc = 0; + + for (unsigned int i = 0; i<len; i++) + { + char c = input[i]; + + if ('/' == c) + sc++; + if (sc < 3) + res[i] = (char) tolower ((int) c); + else + res[i] = c; + } + return res; +} + + +/** + * Normalize "payto://ilp/$NAME" + * URI in @a input. + * + * Converts to lower-case. + * + * @param len number of bytes in @a input + * @param input input URL + * @return NULL on error, otherwise 0-terminated canonicalized URI. + */ +static char * +normalize_payto_ilp (size_t len, + const char input[static len]) +{ + char *res = GNUNET_malloc (len + 1); + + for (unsigned int i = 0; i<len; i++) + { + char c = input[i]; + + res[i] = (char) tolower ((int) c); + } + return res; +} + + +char * +TALER_payto_normalize (const char *input) +{ + char *method; + const char *end; + char *ret; + + { + char *err; + + err = TALER_payto_validate (input); + if (NULL != err) + { + GNUNET_log (GNUNET_ERROR_TYPE_WARNING, + "Malformed payto://-URI `%s': %s\n", + input, + err); + GNUNET_free (err); + return NULL; + } + } + method = TALER_payto_get_method (input); + if (NULL == method) + { + GNUNET_break (0); + return NULL; + } + end = strchr (input, '?'); + if (NULL == end) + end = &input[strlen (input)]; + if (0 == strcasecmp (method, + "x-taler-bank")) + ret = normalize_payto_x_taler_bank (end - input, + input); + else if (0 == strcasecmp (method, + "iban")) + ret = normalize_payto_iban (end - input, + input); + else if (0 == strcasecmp (method, + "upi")) + ret = normalize_payto_upi (end - input, + input); + else if (0 == strcasecmp (method, + "bitcoin")) + ret = normalize_payto_bitcoin (end - input, + input); + else if (0 == strcasecmp (method, + "ilp")) + ret = normalize_payto_ilp (end - input, + input); + else + ret = GNUNET_strndup (input, + end - input); + GNUNET_free (method); + return ret; +} + + void TALER_payto_hash (const char *payto, struct TALER_PaytoHashP *h_payto) @@ -267,9 +642,9 @@ TALER_payto_hash (const char *payto, &sha512); GNUNET_static_assert (sizeof (sha512) > sizeof (*h_payto)); /* truncate */ - memcpy (h_payto, - &sha512, - sizeof (*h_payto)); + GNUNET_memcpy (h_payto, + &sha512, + sizeof (*h_payto)); } diff --git a/src/util/taler-config.in b/src/util/taler-config.in index 07f6401d6..3399aec10 100644 --- a/src/util/taler-config.in +++ b/src/util/taler-config.in @@ -7,7 +7,7 @@ if ! type gnunet-config >/dev/null; then exit 1 fi -GC=`which gnunet-config` -SO=`ls %libdir%/libtalerutil.so.* | sort -n | tail -n1` +GC=$(which gnunet-config) +SO=$(ls %libdir%/libtalerutil.so.* | sort -n | tail -n1) export LD_PRELOAD=${LD_PRELOAD:-}:${SO} exec gnunet-config "$@" diff --git a/src/util/taler-exchange-secmod-cs.c b/src/util/taler-exchange-secmod-cs.c index 2cdf09adf..3e9ba1558 100644 --- a/src/util/taler-exchange-secmod-cs.c +++ b/src/util/taler-exchange-secmod-cs.c @@ -269,7 +269,7 @@ struct BatchJob /** * Result with the signature. */ - struct TALER_BlindedDenominationCsSignAnswer cs_answer; + struct GNUNET_CRYPTO_CsBlindSignature cs_answer; } sign; /** @@ -285,7 +285,7 @@ struct BatchJob /** * Pair of points to return. */ - struct TALER_DenominationCSPublicRPairP rpairp; + struct GNUNET_CRYPTO_CSPublicRPairP rpairp; } rderive; @@ -341,6 +341,13 @@ static struct GNUNET_TIME_Timestamp now_tmp; static char *keydir; /** + * Name of the configuration section prefix to use. Usually either "taler-exchange" or + * "donau". The actual configuration section will then be + * "$SECTION-secmod-cs". + */ +static char *section; + +/** * How much should coin creation (@e duration_withdraw) duration overlap * with the next denomination? Basically, the starting time of two * denominations is always @e duration_withdraw - #overlap_duration apart. @@ -423,9 +430,9 @@ generate_response (struct DenominationKey *dk) &an->secm_sig); an->secm_pub = TES_smpub; p = (void *) &an[1]; - memcpy (p, - denom->section, - nlen); + GNUNET_memcpy (p, + denom->section, + nlen); dk->an = an; } @@ -433,7 +440,7 @@ generate_response (struct DenominationKey *dk) /** * Do the actual signing work. * - * @param h_cs key to sign with + * @param h_cs hash of key to sign with * @param planchet message to sign * @param for_melt true if for melting * @param[out] cs_sigp set to the CS signature @@ -441,9 +448,9 @@ generate_response (struct DenominationKey *dk) */ static enum TALER_ErrorCode do_sign (const struct TALER_CsPubHashP *h_cs, - const struct TALER_BlindedCsPlanchet *planchet, + const struct GNUNET_CRYPTO_CsBlindedMessage *planchet, bool for_melt, - struct TALER_BlindedDenominationCsSignAnswer *cs_sigp) + struct GNUNET_CRYPTO_CsBlindSignature *cs_sigp) { struct GNUNET_CRYPTO_CsRSecret r[2]; struct DenominationKey *dk; @@ -473,15 +480,14 @@ do_sign (const struct TALER_CsPubHashP *h_cs, GNUNET_assert (dk->rc < UINT_MAX); dk->rc++; GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); - GNUNET_CRYPTO_cs_r_derive (&planchet->nonce.nonce, + GNUNET_CRYPTO_cs_r_derive (&planchet->nonce, for_melt ? "rm" : "rw", &dk->denom_priv, r); - cs_sigp->b = GNUNET_CRYPTO_cs_sign_derive (&dk->denom_priv, - r, - planchet->c, - &planchet->nonce.nonce, - &cs_sigp->s_scalar); + GNUNET_CRYPTO_cs_sign_derive (&dk->denom_priv, + r, + planchet, + cs_sigp); GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); GNUNET_assert (dk->rc > 0); dk->rc--; @@ -543,14 +549,14 @@ fail_derive (struct TES_Client *client, */ static enum GNUNET_GenericReturnValue send_signature (struct TES_Client *client, - const struct TALER_BlindedDenominationCsSignAnswer *cs_answer) + const struct GNUNET_CRYPTO_CsBlindSignature *cs_answer) { struct TALER_CRYPTO_SignResponse sres; sres.header.size = htons (sizeof (sres)); sres.header.type = htons (TALER_HELPER_CS_MT_RES_SIGNATURE); - sres.reserved = htonl (0); - sres.cs_answer = *cs_answer; + sres.b = htonl (cs_answer->b); + sres.cs_answer = cs_answer->s_scalar; return TES_transmit (client->csock, &sres.header); } @@ -569,13 +575,13 @@ static enum GNUNET_GenericReturnValue handle_sign_request (struct TES_Client *client, const struct TALER_CRYPTO_CsSignRequestMessage *sr) { - struct TALER_BlindedDenominationCsSignAnswer cs_answer; + struct GNUNET_CRYPTO_CsBlindSignature cs_answer; struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); enum TALER_ErrorCode ec; enum GNUNET_GenericReturnValue ret; ec = do_sign (&sr->h_cs, - &sr->planchet, + &sr->message, (0 != ntohl (sr->for_melt)), &cs_answer); if (TALER_EC_NONE != ec) @@ -605,12 +611,12 @@ handle_sign_request (struct TES_Client *client, */ static enum TALER_ErrorCode do_derive (const struct TALER_CsPubHashP *h_cs, - const struct TALER_CsNonce *nonce, + const struct GNUNET_CRYPTO_CsSessionNonce *nonce, bool for_melt, - struct TALER_DenominationCSPublicRPairP *rpairp) + struct GNUNET_CRYPTO_CSPublicRPairP *rpairp) { struct DenominationKey *dk; - struct TALER_DenominationCSPrivateRPairP r_priv; + struct GNUNET_CRYPTO_CSPrivateRPairP r_priv; GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); dk = GNUNET_CONTAINER_multihashmap_get (keys, @@ -637,7 +643,7 @@ do_derive (const struct TALER_CsPubHashP *h_cs, GNUNET_assert (dk->rc < UINT_MAX); dk->rc++; GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); - GNUNET_CRYPTO_cs_r_derive (&nonce->nonce, + GNUNET_CRYPTO_cs_r_derive (nonce, for_melt ? "rm" : "rw", &dk->denom_priv, r_priv.r); @@ -662,10 +668,10 @@ do_derive (const struct TALER_CsPubHashP *h_cs, */ static enum GNUNET_GenericReturnValue send_derivation (struct TES_Client *client, - const struct TALER_DenominationCSPublicRPairP *r_pub) + const struct GNUNET_CRYPTO_CSPublicRPairP *r_pub) { struct TALER_CRYPTO_RDeriveResponse rdr = { - .header.size = htons (sizeof (struct TALER_CRYPTO_RDeriveResponse)), + .header.size = htons (sizeof (rdr)), .header.type = htons (TALER_HELPER_CS_MT_RES_RDERIVE), .r_pub = *r_pub }; @@ -776,7 +782,7 @@ worker (void *cls) = bj->details.sign.sr; bj->ec = do_sign (&sr->h_cs, - &sr->planchet, + &sr->message, (0 != ntohl (sr->for_melt)), &bj->details.sign.cs_answer); break; @@ -1093,8 +1099,9 @@ setup_key (struct DenominationKey *dk, GNUNET_CRYPTO_cs_private_key_generate (&priv); GNUNET_CRYPTO_cs_private_key_get_public (&priv, &pub); - TALER_cs_pub_hash (&pub, - &dk->h_cs); + GNUNET_CRYPTO_hash (&pub, + sizeof (pub), + &dk->h_cs.hash); GNUNET_asprintf (&dk->filename, "%s/%s/%llu", keydir, @@ -1242,7 +1249,7 @@ static enum GNUNET_GenericReturnValue handle_r_derive_request (struct TES_Client *client, const struct TALER_CRYPTO_CsRDeriveRequest *rdr) { - struct TALER_DenominationCSPublicRPairP r_pub; + struct GNUNET_CRYPTO_CSPublicRPairP r_pub; struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); enum TALER_ErrorCode ec; enum GNUNET_GenericReturnValue ret; @@ -1373,9 +1380,9 @@ cs_client_init (struct TES_Client *client) NULL != dk; dk = dk->next) { - memcpy (&buf[obs], - dk->an, - ntohs (dk->an->header.size)); + GNUNET_memcpy (&buf[obs], + dk->an, + ntohs (dk->an->header.size)); obs += ntohs (dk->an->header.size); } } @@ -1472,18 +1479,18 @@ cs_update_client_keys (struct TES_Client *client) .h_cs = key->h_cs }; - memcpy (&buf[obs], - &pn, - sizeof (pn)); + GNUNET_memcpy (&buf[obs], + &pn, + sizeof (pn)); GNUNET_assert (obs + sizeof (pn) > obs); obs += sizeof (pn); } else { - memcpy (&buf[obs], - key->an, - ntohs (key->an->header.size)); + GNUNET_memcpy (&buf[obs], + key->an, + ntohs (key->an->header.size)); GNUNET_assert (obs + ntohs (key->an->header.size) > obs); obs += ntohs (key->an->header.size); @@ -1773,20 +1780,19 @@ parse_key (struct Denomination *denom, return; } { - struct GNUNET_CRYPTO_CsPublicKey pub; struct DenominationKey *dk; struct DenominationKey *before; - GNUNET_CRYPTO_cs_private_key_get_public (priv, - &pub); dk = GNUNET_new (struct DenominationKey); dk->denom_priv = *priv; dk->denom = denom; dk->anchor = anchor; dk->filename = GNUNET_strdup (filename); - TALER_cs_pub_hash (&pub, - &dk->h_cs); - dk->denom_pub = pub; + GNUNET_CRYPTO_cs_private_key_get_public (priv, + &dk->denom_pub); + GNUNET_CRYPTO_hash (&dk->denom_pub, + sizeof (dk->denom_pub), + &dk->h_cs.hash); generate_response (dk); if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put ( @@ -1808,7 +1814,9 @@ parse_key (struct Denomination *denom, NULL != pos; pos = pos->next) { - if (GNUNET_TIME_timestamp_cmp (pos->anchor, >, anchor)) + if (GNUNET_TIME_timestamp_cmp (pos->anchor, + >, + anchor)) break; before = pos; } @@ -1956,6 +1964,11 @@ parse_denomination_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, const char *ct, struct Denomination *denom) { + char *secname; + + GNUNET_asprintf (&secname, + "%s-secmod-cs", + section); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, ct, @@ -1965,6 +1978,7 @@ parse_denomination_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, ct, "DURATION_WITHDRAW"); + GNUNET_free (secname); return GNUNET_SYSERR; } if (GNUNET_TIME_relative_cmp (overlap_duration, @@ -1972,11 +1986,13 @@ parse_denomination_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, denom->duration_withdraw)) { GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-cs", + secname, "OVERLAP_DURATION", "Value given must be smaller than value for DURATION_WITHDRAW!"); + GNUNET_free (secname); return GNUNET_SYSERR; } + GNUNET_free (secname); denom->section = GNUNET_strdup (ct); return GNUNET_OK; } @@ -2091,28 +2107,36 @@ load_denominations (void *cls, static enum GNUNET_GenericReturnValue load_durations (const struct GNUNET_CONFIGURATION_Handle *cfg) { + char *secname; + + GNUNET_asprintf (&secname, + "%s-secmod-cs", + section); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, - "taler-exchange-secmod-cs", + secname, "OVERLAP_DURATION", &overlap_duration)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-cs", + secname, "OVERLAP_DURATION"); + GNUNET_free (secname); return GNUNET_SYSERR; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, - "taler-exchange-secmod-cs", + secname, "LOOKAHEAD_SIGN", &lookahead_sign)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-cs", + secname, "LOOKAHEAD_SIGN"); + GNUNET_free (secname); return GNUNET_SYSERR; } + GNUNET_free (secname); return GNUNET_OK; } @@ -2156,6 +2180,7 @@ run (void *cls, .updater = &cs_update_client_keys, .init = &cs_client_init }; + char *secname; (void) cls; (void) args; @@ -2170,27 +2195,40 @@ run (void *cls, /* get current time again, we may be timetraveling! */ now = GNUNET_TIME_timestamp_get (); } + GNUNET_asprintf (&secname, + "%s-secmod-cs", + section); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, - "taler-exchange-secmod-cs", + secname, "KEY_DIR", &keydir)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-cs", + secname, "KEY_DIR"); + GNUNET_free (secname); global_ret = EXIT_NOTCONFIGURED; return; } + GNUNET_free (secname); if (GNUNET_OK != load_durations (cfg)) { global_ret = EXIT_NOTCONFIGURED; return; } - global_ret = TES_listen_start (cfg, - "taler-exchange-secmod-cs", - &cb); + { + char *secname; + + GNUNET_asprintf (&secname, + "%s-secmod-cs", + section); + global_ret = TES_listen_start (cfg, + secname, + &cb); + GNUNET_free (secname); + } if (0 != global_ret) return; sem_init (&worker_sem, @@ -2263,6 +2301,11 @@ main (int argc, char **argv) { struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_option_string ('s', + "section", + "SECTION", + "name of the configuration section prefix to use, default is 'taler'", + §ion), GNUNET_GETOPT_option_timetravel ('T', "timetravel"), GNUNET_GETOPT_option_timestamp ('t', @@ -2281,7 +2324,7 @@ main (int argc, /* Restrict permissions for the key files that we create. */ (void) umask (S_IWGRP | S_IROTH | S_IWOTH | S_IXOTH); - + section = GNUNET_strdup ("taler-exchange"); /* force linker to link against libtalerutil; if we do not do this, the linker may "optimize" libtalerutil away and skip #TALER_OS_init(), which we do need */ diff --git a/src/util/taler-exchange-secmod-cs.conf b/src/util/taler-exchange-secmod-cs.conf index 5085eab79..fa3cdba40 100644 --- a/src/util/taler-exchange-secmod-cs.conf +++ b/src/util/taler-exchange-secmod-cs.conf @@ -8,16 +8,16 @@ OVERLAP_DURATION = 5 m # Where do we store the generated private keys. -KEY_DIR = ${TALER_DATA_HOME}/exchange-secmod-cs/keys +KEY_DIR = ${TALER_DATA_HOME}exchange-secmod-cs/keys # Where does the helper listen for requests? -UNIXPATH = $TALER_RUNTIME_DIR/exchange-secmod-cs/server.sock +UNIXPATH = ${TALER_RUNTIME_DIR}exchange-secmod-cs/server.sock # Directory for clients. -CLIENT_DIR = $TALER_RUNTIME_DIR/exchange-secmod-cs/clients +CLIENT_DIR = ${TALER_RUNTIME_DIR}exchange-secmod-cs/clients # Where should the security module store its own private key? -SM_PRIV_KEY = ${TALER_DATA_HOME}/exchange-secmod-cs/secmod-private-key +SM_PRIV_KEY = ${TALER_DATA_HOME}exchange-secmod-cs/secmod-private-key # For how long into the future do we pre-generate keys? LOOKAHEAD_SIGN = 1 year diff --git a/src/util/taler-exchange-secmod-cs.h b/src/util/taler-exchange-secmod-cs.h index fd550efbc..0321335da 100644 --- a/src/util/taler-exchange-secmod-cs.h +++ b/src/util/taler-exchange-secmod-cs.h @@ -136,9 +136,9 @@ struct TALER_CRYPTO_CsSignRequestMessage struct TALER_CsPubHashP h_cs; /** - * Planchet containing message to sign and nonce to derive R from + * Message to sign. */ - struct TALER_BlindedCsPlanchet planchet; + struct GNUNET_CRYPTO_CsBlindedMessage message; }; @@ -188,7 +188,7 @@ struct TALER_CRYPTO_CsRDeriveRequest /** * Withdraw nonce to derive R from */ - struct TALER_CsNonce nonce; + struct GNUNET_CRYPTO_CsSessionNonce nonce; }; @@ -248,14 +248,14 @@ struct TALER_CRYPTO_SignResponse struct GNUNET_MessageHeader header; /** - * For now, always zero. + * The chosen 'b' (0 or 1). */ - uint32_t reserved; + uint32_t b; /** - * Contains the blindided s and the chosen b + * Contains the blindided s. */ - struct TALER_BlindedDenominationCsSignAnswer cs_answer; + struct GNUNET_CRYPTO_CsBlindS cs_answer; }; /** @@ -274,9 +274,9 @@ struct TALER_CRYPTO_RDeriveResponse uint32_t reserved; /** - * derived R + * Pair of derived R values */ - struct TALER_DenominationCSPublicRPairP r_pub; + struct GNUNET_CRYPTO_CSPublicRPairP r_pub; }; diff --git a/src/util/taler-exchange-secmod-eddsa.c b/src/util/taler-exchange-secmod-eddsa.c index e07e9a71d..0b95447f7 100644 --- a/src/util/taler-exchange-secmod-eddsa.c +++ b/src/util/taler-exchange-secmod-eddsa.c @@ -137,6 +137,13 @@ static struct GNUNET_TIME_Timestamp now_tmp; static char *keydir; /** + * Name of the configuration section prefix to use. Usually either "taler-exchange" or + * "donau". The actual configuration section will then be + * "$SECTION-secmod-eddsa". + */ +static char *section; + +/** * How much should coin creation duration overlap * with the next key? Basically, the starting time of two * keys is always #duration - #overlap_duration apart. @@ -584,11 +591,11 @@ eddsa_client_init (struct TES_Client *client) static enum GNUNET_GenericReturnValue eddsa_update_client_keys (struct TES_Client *client) { + GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Updating client %p to generation %llu\n", client, (unsigned long long) key_gen); - GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); for (struct Key *key = keys_head; NULL != key; key = key->next) @@ -826,9 +833,9 @@ parse_key (const char *filename, filename); return GNUNET_SYSERR; } - memcpy (&priv, - buf, - buf_size); + GNUNET_memcpy (&priv, + buf, + buf_size); { struct GNUNET_CRYPTO_EddsaPublicKey pub; @@ -991,39 +998,48 @@ import_key (void *cls, static enum GNUNET_GenericReturnValue load_durations (const struct GNUNET_CONFIGURATION_Handle *cfg) { + char *secname; + + GNUNET_asprintf (&secname, + "%s-secmod-eddsa", + section); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, - "taler-exchange-secmod-eddsa", + secname, "OVERLAP_DURATION", &overlap_duration)) { + GNUNET_free (secname); GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-eddsa", + secname, "OVERLAP_DURATION"); return GNUNET_SYSERR; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, - "taler-exchange-secmod-eddsa", + secname, "DURATION", &duration)) { + GNUNET_free (secname); GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-eddsa", + secname, "DURATION"); return GNUNET_SYSERR; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, - "taler-exchange-secmod-eddsa", + secname, "LOOKAHEAD_SIGN", &lookahead_sign)) { + GNUNET_free (secname); GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-eddsa", + secname, "LOOKAHEAD_SIGN"); return GNUNET_SYSERR; } + GNUNET_free (secname); return GNUNET_OK; } @@ -1065,6 +1081,7 @@ run (void *cls, .updater = eddsa_update_client_keys, .init = eddsa_client_init }; + char *secname; (void) cls; (void) args; @@ -1079,6 +1096,9 @@ run (void *cls, /* get current time again, we may be timetraveling! */ now = GNUNET_TIME_timestamp_get (); } + GNUNET_asprintf (&secname, + "%s-secmod-eddsa", + section); if (GNUNET_OK != load_durations (cfg)) { @@ -1087,21 +1107,31 @@ run (void *cls, } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, - "taler-exchange-secmod-eddsa", + secname, "KEY_DIR", &keydir)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-eddsa", + secname, "KEY_DIR"); + GNUNET_free (secname); global_ret = EXIT_NOTCONFIGURED; return; } + GNUNET_free (secname); GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL); - global_ret = TES_listen_start (cfg, - "taler-exchange-secmod-eddsa", - &cb); + { + char *secname; + + GNUNET_asprintf (&secname, + "%s-secmod-eddsa", + section); + global_ret = TES_listen_start (cfg, + secname, + &cb); + GNUNET_free (secname); + } if (0 != global_ret) return; /* Load keys */ @@ -1144,6 +1174,11 @@ main (int argc, char **argv) { struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_option_string ('s', + "section", + "SECTION", + "name of the configuration section prefix to use, default is 'taler'", + §ion), GNUNET_GETOPT_option_timetravel ('T', "timetravel"), GNUNET_GETOPT_option_timestamp ('t', @@ -1157,7 +1192,7 @@ main (int argc, /* Restrict permissions for the key files that we create. */ (void) umask (S_IWGRP | S_IROTH | S_IWOTH | S_IXOTH); - + section = GNUNET_strdup ("taler-exchange"); /* force linker to link against libtalerutil; if we do not do this, the linker may "optimize" libtalerutil away and skip #TALER_OS_init(), which we do need */ diff --git a/src/util/taler-exchange-secmod-eddsa.conf b/src/util/taler-exchange-secmod-eddsa.conf index ea09f0334..0cb4a4ffc 100644 --- a/src/util/taler-exchange-secmod-eddsa.conf +++ b/src/util/taler-exchange-secmod-eddsa.conf @@ -8,16 +8,16 @@ OVERLAP_DURATION = 5m # Where do we store the private keys. -KEY_DIR = ${TALER_DATA_HOME}/exchange-secmod-eddsa/keys +KEY_DIR = ${TALER_DATA_HOME}exchange-secmod-eddsa/keys # Where does the helper listen for requests? -UNIXPATH = $TALER_RUNTIME_DIR/exchange-secmod-eddsa/server.sock +UNIXPATH = ${TALER_RUNTIME_DIR}exchange-secmod-eddsa/server.sock # Directory for clients. -CLIENT_DIR = $TALER_RUNTIME_DIR/exchange-secmod-eddsa/clients +CLIENT_DIR = ${TALER_RUNTIME_DIR}exchange-secmod-eddsa/clients # Where should the security module store its own private key? -SM_PRIV_KEY = ${TALER_DATA_HOME}/exchange-secmod-eddsa/secmod-private-key +SM_PRIV_KEY = ${TALER_DATA_HOME}exchange-secmod-eddsa/secmod-private-key # For how long into the future do we pre-generate keys? LOOKAHEAD_SIGN = 1 year diff --git a/src/util/taler-exchange-secmod-rsa.c b/src/util/taler-exchange-secmod-rsa.c index c651d78a8..c80e2e3c4 100644 --- a/src/util/taler-exchange-secmod-rsa.c +++ b/src/util/taler-exchange-secmod-rsa.c @@ -308,6 +308,13 @@ static struct GNUNET_TIME_Timestamp now_tmp; static char *keydir; /** + * Name of the configuration section prefix to use. Usually either "taler-exchange" or + * "donau". The actual configuration section will then be + * "$SECTION-secmod-rsa". + */ +static char *section; + +/** * How much should coin creation (@e duration_withdraw) duration overlap * with the next denomination? Basically, the starting time of two * denominations is always @e duration_withdraw - #overlap_duration apart. @@ -394,13 +401,13 @@ generate_response (struct DenominationKey *dk) &an->secm_sig); an->secm_pub = TES_smpub; p = (void *) &an[1]; - memcpy (p, - buf, - buf_len); + GNUNET_memcpy (p, + buf, + buf_len); GNUNET_free (buf); - memcpy (p + buf_len, - denom->section, - nlen); + GNUNET_memcpy (p + buf_len, + denom->section, + nlen); dk->an = an; } @@ -409,15 +416,13 @@ generate_response (struct DenominationKey *dk) * Do the actual signing work. * * @param h_rsa key to sign with - * @param blinded_msg message to sign - * @param blinded_msg_size number of bytes in @a blinded_msg + * @param bm blinded message to sign * @param[out] rsa_signaturep set to the RSA signature * @return #TALER_EC_NONE on success */ static enum TALER_ErrorCode do_sign (const struct TALER_RsaPubHashP *h_rsa, - const void *blinded_msg, - size_t blinded_msg_size, + const struct GNUNET_CRYPTO_RsaBlindedMessage *bm, struct GNUNET_CRYPTO_RsaSignature **rsa_signaturep) { struct DenominationKey *dk; @@ -447,15 +452,14 @@ do_sign (const struct TALER_RsaPubHashP *h_rsa, GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received request to sign over %u bytes with key %s\n", - (unsigned int) blinded_msg_size, + (unsigned int) bm->blinded_msg_size, GNUNET_h2s (&h_rsa->hash)); GNUNET_assert (dk->rc < UINT_MAX); dk->rc++; GNUNET_assert (0 == pthread_mutex_unlock (&keys_lock)); rsa_signature = GNUNET_CRYPTO_rsa_sign_blinded (dk->denom_priv, - blinded_msg, - blinded_msg_size); + bm); GNUNET_assert (0 == pthread_mutex_lock (&keys_lock)); GNUNET_assert (dk->rc > 0); dk->rc--; @@ -524,9 +528,9 @@ send_signature (struct TES_Client *client, sr = GNUNET_malloc (tsize); sr->header.size = htons (tsize); sr->header.type = htons (TALER_HELPER_RSA_MT_RES_SIGNATURE); - memcpy (&sr[1], - buf, - buf_size); + GNUNET_memcpy (&sr[1], + buf, + buf_size); GNUNET_free (buf); ret = TES_transmit (client->csock, &sr->header); @@ -548,14 +552,15 @@ static enum GNUNET_GenericReturnValue handle_sign_request (struct TES_Client *client, const struct TALER_CRYPTO_SignRequest *sr) { - const void *blinded_msg = &sr[1]; - size_t blinded_msg_size = ntohs (sr->header.size) - sizeof (*sr); + struct GNUNET_CRYPTO_RsaBlindedMessage bm = { + .blinded_msg = (void *) &sr[1], + .blinded_msg_size = ntohs (sr->header.size) - sizeof (*sr) + }; struct GNUNET_CRYPTO_RsaSignature *rsa_signature; enum TALER_ErrorCode ec; ec = do_sign (&sr->h_rsa, - blinded_msg, - blinded_msg_size, + &bm, &rsa_signature); if (TALER_EC_NONE != ec) { @@ -660,12 +665,13 @@ worker (void *cls) { struct BatchJob *bj = w->job; const struct TALER_CRYPTO_SignRequest *sr = bj->sr; - const void *blinded_msg = &sr[1]; - size_t blinded_msg_size = ntohs (sr->header.size) - sizeof (*sr); + struct GNUNET_CRYPTO_RsaBlindedMessage bm = { + .blinded_msg = (void *) &sr[1], + .blinded_msg_size = ntohs (sr->header.size) - sizeof (*sr) + }; bj->ec = do_sign (&sr->h_rsa, - blinded_msg, - blinded_msg_size, + &bm, &bj->rsa_signature); sem_up (&bj->sem); w->job = NULL; @@ -880,8 +886,8 @@ setup_key (struct DenominationKey *dk, } buf_size = GNUNET_CRYPTO_rsa_private_key_encode (priv, &buf); - TALER_rsa_pub_hash (pub, - &dk->h_rsa); + GNUNET_CRYPTO_rsa_public_key_hash (pub, + &dk->h_rsa.hash); GNUNET_asprintf (&dk->filename, "%s/%s/%llu", keydir, @@ -1111,9 +1117,9 @@ rsa_client_init (struct TES_Client *client) NULL != dk; dk = dk->next) { - memcpy (&buf[obs], - dk->an, - ntohs (dk->an->header.size)); + GNUNET_memcpy (&buf[obs], + dk->an, + ntohs (dk->an->header.size)); GNUNET_assert (obs + ntohs (dk->an->header.size) > obs); obs += ntohs (dk->an->header.size); @@ -1212,18 +1218,18 @@ rsa_update_client_keys (struct TES_Client *client) .h_rsa = key->h_rsa }; - memcpy (&buf[obs], - &pn, - sizeof (pn)); + GNUNET_memcpy (&buf[obs], + &pn, + sizeof (pn)); GNUNET_assert (obs + sizeof (pn) > obs); obs += sizeof (pn); } else { - memcpy (&buf[obs], - key->an, - ntohs (key->an->header.size)); + GNUNET_memcpy (&buf[obs], + key->an, + ntohs (key->an->header.size)); GNUNET_assert (obs + ntohs (key->an->header.size) > obs); obs += ntohs (key->an->header.size); @@ -1255,6 +1261,7 @@ create_key (struct Denomination *denom, struct GNUNET_TIME_Timestamp anchor; anchor = now; + // FIXME: round down to multiple of 'anchor_round' value from configuration if (NULL != denom->keys_tail) { struct GNUNET_TIME_Absolute abs; @@ -1545,8 +1552,8 @@ parse_key (struct Denomination *denom, dk->denom = denom; dk->anchor = anchor; dk->filename = GNUNET_strdup (filename); - TALER_rsa_pub_hash (pub, - &dk->h_rsa); + GNUNET_CRYPTO_rsa_public_key_hash (pub, + &dk->h_rsa.hash); dk->denom_pub = pub; generate_response (dk); if (GNUNET_OK != @@ -1723,7 +1730,11 @@ parse_denomination_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, struct Denomination *denom) { unsigned long long rsa_keysize; + char *secname; + GNUNET_asprintf (&secname, + "%s-secmod-rsa", + section); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, ct, @@ -1733,6 +1744,7 @@ parse_denomination_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, ct, "DURATION_WITHDRAW"); + GNUNET_free (secname); return GNUNET_SYSERR; } if (GNUNET_TIME_relative_cmp (overlap_duration, @@ -1740,9 +1752,10 @@ parse_denomination_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, denom->duration_withdraw)) { GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-rsa", + section, "OVERLAP_DURATION", "Value given must be smaller than value for DURATION_WITHDRAW!"); + GNUNET_free (secname); return GNUNET_SYSERR; } if (GNUNET_OK != @@ -1754,6 +1767,7 @@ parse_denomination_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, ct, "RSA_KEYSIZE"); + GNUNET_free (secname); return GNUNET_SYSERR; } if ( (rsa_keysize > 4 * 2048) || @@ -1763,8 +1777,10 @@ parse_denomination_cfg (const struct GNUNET_CONFIGURATION_Handle *cfg, ct, "RSA_KEYSIZE", "Given RSA keysize outside of permitted range [1024,8192]\n"); + GNUNET_free (secname); return GNUNET_SYSERR; } + GNUNET_free (secname); denom->rsa_keysize = (unsigned int) rsa_keysize; denom->section = GNUNET_strdup (ct); return GNUNET_OK; @@ -1879,28 +1895,36 @@ load_denominations (void *cls, static enum GNUNET_GenericReturnValue load_durations (const struct GNUNET_CONFIGURATION_Handle *cfg) { + char *secname; + + GNUNET_asprintf (&secname, + "%s-secmod-rsa", + section); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, - "taler-exchange-secmod-rsa", + secname, "OVERLAP_DURATION", &overlap_duration)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-rsa", + secname, "OVERLAP_DURATION"); + GNUNET_free (secname); return GNUNET_SYSERR; } if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (cfg, - "taler-exchange-secmod-rsa", + secname, "LOOKAHEAD_SIGN", &lookahead_sign)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-rsa", + secname, "LOOKAHEAD_SIGN"); + GNUNET_free (secname); return GNUNET_SYSERR; } + GNUNET_free (secname); return GNUNET_OK; } @@ -1944,6 +1968,7 @@ run (void *cls, .updater = rsa_update_client_keys, .init = rsa_client_init }; + char *secname; (void) cls; (void) args; @@ -1958,27 +1983,40 @@ run (void *cls, /* get current time again, we may be timetraveling! */ now = GNUNET_TIME_timestamp_get (); } + GNUNET_asprintf (&secname, + "%s-secmod-rsa", + section); if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, - "taler-exchange-secmod-rsa", + secname, "KEY_DIR", &keydir)) { GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, - "taler-exchange-secmod-rsa", + secname, "KEY_DIR"); + GNUNET_free (secname); global_ret = EXIT_NOTCONFIGURED; return; } + GNUNET_free (secname); if (GNUNET_OK != load_durations (cfg)) { global_ret = EXIT_NOTCONFIGURED; return; } - global_ret = TES_listen_start (cfg, - "taler-exchange-secmod-rsa", - &cb); + { + char *secname; + + GNUNET_asprintf (&secname, + "%s-secmod-rsa", + section); + global_ret = TES_listen_start (cfg, + secname, + &cb); + GNUNET_free (secname); + } if (0 != global_ret) return; sem_init (&worker_sem, @@ -2052,6 +2090,11 @@ main (int argc, char **argv) { struct GNUNET_GETOPT_CommandLineOption options[] = { + GNUNET_GETOPT_option_string ('s', + "section", + "SECTION", + "name of the configuration section prefix to use, default is 'taler'", + §ion), GNUNET_GETOPT_option_timetravel ('T', "timetravel"), GNUNET_GETOPT_option_timestamp ('t', @@ -2070,7 +2113,7 @@ main (int argc, /* Restrict permissions for the key files that we create. */ (void) umask (S_IWGRP | S_IROTH | S_IWOTH | S_IXOTH); - + section = GNUNET_strdup ("taler-exchange"); /* force linker to link against libtalerutil; if we do not do this, the linker may "optimize" libtalerutil away and skip #TALER_OS_init(), which we do need */ diff --git a/src/util/taler-exchange-secmod-rsa.conf b/src/util/taler-exchange-secmod-rsa.conf index dfa87f050..978c40258 100644 --- a/src/util/taler-exchange-secmod-rsa.conf +++ b/src/util/taler-exchange-secmod-rsa.conf @@ -5,19 +5,22 @@ # wallets picking one key and then due to network latency # another key being valid. The DURATION_WITHDRAW period # must be longer than this value. -OVERLAP_DURATION = 5 m +OVERLAP_DURATION = 0 m # Where do we store the generated private keys. -KEY_DIR = ${TALER_DATA_HOME}/exchange-secmod-rsa/keys +KEY_DIR = ${TALER_DATA_HOME}exchange-secmod-rsa/keys # Where does the helper listen for requests? -UNIXPATH = $TALER_RUNTIME_DIR/exchange-secmod-rsa/server.sock +UNIXPATH = ${TALER_RUNTIME_DIR}exchange-secmod-rsa/server.sock # Directory for clients. -CLIENT_DIR = $TALER_RUNTIME_DIR/exchange-secmod-rsa/clients +CLIENT_DIR = ${TALER_RUNTIME_DIR}exchange-secmod-rsa/clients # Where should the security module store its own private key? -SM_PRIV_KEY = ${TALER_DATA_HOME}/exchange-secmod-rsa/secmod-private-key +SM_PRIV_KEY = ${TALER_DATA_HOME}exchange-secmod-rsa/secmod-private-key # For how long into the future do we pre-generate keys? LOOKAHEAD_SIGN = 1 year + +# Round down anchor key start date to multiples of this time. +ANCHOR_ROUND = 1 ms
\ No newline at end of file diff --git a/src/util/test_age_restriction.c b/src/util/test_age_restriction.c index 77717616f..61499e5e0 100644 --- a/src/util/test_age_restriction.c +++ b/src/util/test_age_restriction.c @@ -21,11 +21,7 @@ */ #include "platform.h" #include "taler_util.h" - -extern uint8_t -get_age_group ( - const struct TALER_AgeMask *mask, - uint8_t age); +#include <gnunet/gnunet_common.h> /** * Encodes the age mask into a string, like "8:10:12:14:16:18:21" @@ -84,24 +80,24 @@ test_groups (void) .bits = 1 | 1 << 5 | 1 << 13 | 1 << 23, - .group = { 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 } + .group = { 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 } }, { .bits = 1 | 1 << 8 | 1 << 10 | 1 << 12 | 1 << 14 | 1 << 16 | 1 << 18 | 1 << 21, - .group = { 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, - 2, 2, - 3, 3, - 4, 4, - 5, 5, - 6, 6, 6, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7} + .group = { 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, + 2, 2, + 3, 3, + 4, 4, + 5, 5, + 6, 6, 6, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7} } @@ -113,10 +109,10 @@ test_groups (void) for (uint8_t i = 0; i < 32; i++) { - uint8_t r = get_age_group (&mask, i); + uint8_t r = TALER_get_age_group (&mask, i); char *m = age_mask_to_string (&mask); - printf ("get_age_group(%s, %2d) = %d vs %d (exp)\n", + printf ("TALER_get_age_group(%s, %2d) = %d vs %d (exp)\n", m, i, r, @@ -133,6 +129,177 @@ test_groups (void) } +enum GNUNET_GenericReturnValue +test_dates (void) +{ + struct TALER_AgeMask mask = { + .bits = 1 | 1 << 5 | 1 << 9 | 1 << 13 | 1 << 17 | 1 << 21 + }; + struct + { + char *date; + uint32_t expected; + enum GNUNET_GenericReturnValue ret; + } + test [] = { + {.date = "abcd-00-00", .expected = 0, .ret = GNUNET_SYSERR}, + {.date = "1900-00-01", .expected = 0, .ret = GNUNET_SYSERR}, + {.date = "19000001", .expected = 0, .ret = GNUNET_SYSERR}, + {.date = "2001-33-05", .expected = 0, .ret = GNUNET_SYSERR}, + {.date = "2001-33-35", .expected = 0, .ret = GNUNET_SYSERR}, + + {.date = "1900-00-00", .expected = 0, .ret = GNUNET_OK}, + {.date = "2001-00-00", .expected = 0, .ret = GNUNET_OK}, + {.date = "2001-03-00", .expected = 0, .ret = GNUNET_OK}, + {.date = "2001-03-05", .expected = 0, .ret = GNUNET_OK}, + + /* These dates should be far enough for the near future so that + * the expected values are correct. Will need adjustment in 2044 :) */ + {.date = "2022-11-26", .expected = 19322, .ret = GNUNET_OK }, + {.date = "2022-11-27", .expected = 19323, .ret = GNUNET_OK }, + {.date = "2023-06-26", .expected = 19534, .ret = GNUNET_OK }, + {.date = "2023-06-01", .expected = 19509, .ret = GNUNET_OK }, + {.date = "2023-06-00", .expected = 19509, .ret = GNUNET_OK }, + {.date = "2023-01-01", .expected = 19358, .ret = GNUNET_OK }, + {.date = "2023-00-00", .expected = 19358, .ret = GNUNET_OK }, + + /* Special case: .date == NULL meands birthday == current date, which + * should be 21 years in the future. We will set these values below in the + * loop */ + {.date = NULL, .expected = 0, .ret = GNUNET_OK }, + }; + char buf[256] = {0}; + + for (uint8_t t = 0; t < sizeof(test) / sizeof(test[0]); t++) + { + uint32_t d; + enum GNUNET_GenericReturnValue ret; + char *date = test[t].date; + + if (NULL == test[t].date) + { + /* Special case: We set .date to the current date. */ + time_t tn; + struct tm now; + + time (&tn); + localtime_r (&tn, &now); + strftime (buf, sizeof(buf), "%Y-%m-%d", &now); + date = &buf[0]; + + /* The expected value is the number of days since 1970-01-01, + * counted simplistically */ + test[t].expected = timegm (&now) / 60 / 60 / 24; + } + + ret = TALER_parse_coarse_date (date, + &mask, + &d); + if (ret != test[t].ret) + { + printf ( + "dates[%d] for date `%s` expected parser to return: %d, got: %d\n", + t, date, test[t].ret, ret); + return GNUNET_SYSERR; + } + + if (ret == GNUNET_SYSERR) + continue; + + if (d != test[t].expected) + { + printf ( + "dates[%d] for date `%s` expected value %d, but got %d\n", + t, date, test[t].expected, d); + return GNUNET_SYSERR; + } + + printf ("dates[%d] for date `%s` got expected value %d\n", + t, date, d); + } + + printf ("done with dates\n"); + + return GNUNET_OK; +} + + +enum GNUNET_GenericReturnValue +test_lowest (void) +{ + struct TALER_AgeMask mask = { + .bits = 1 | 1 << 5 | 1 << 9 | 1 << 13 | 1 << 17 | 1 << 21 + }; + + struct { uint8_t age; uint8_t expected; } + test [] = { + {.age = 1, .expected = 0 }, + {.age = 2, .expected = 0 }, + {.age = 3, .expected = 0 }, + {.age = 4, .expected = 0 }, + {.age = 5, .expected = 5 }, + {.age = 6, .expected = 5 }, + {.age = 7, .expected = 5 }, + {.age = 8, .expected = 5 }, + {.age = 9, .expected = 9 }, + {.age = 10, .expected = 9 }, + {.age = 11, .expected = 9 }, + {.age = 12, .expected = 9 }, + {.age = 13, .expected = 13 }, + {.age = 14, .expected = 13 }, + {.age = 15, .expected = 13 }, + {.age = 16, .expected = 13 }, + {.age = 17, .expected = 17 }, + {.age = 18, .expected = 17 }, + {.age = 19, .expected = 17 }, + {.age = 20, .expected = 17 }, + {.age = 21, .expected = 21 }, + {.age = 22, .expected = 21 }, + }; + + for (uint8_t n = 0; n < sizeof(test) / sizeof(test[0]); n++) + { + uint8_t l = TALER_get_lowest_age (&mask, test[n].age); + printf ("lowest[%d] for age %d, expected lowest: %d, got: %d\n", + n, test[n].age, test[n].expected, l); + if (test[n].expected != l) + return GNUNET_SYSERR; + } + + return GNUNET_OK; +} + + +enum GNUNET_GenericReturnValue +test_adult (void) +{ + struct { struct TALER_AgeMask mask; uint8_t expected; } + test[] = { + { .mask = {.bits = 1 | 1 << 2}, + .expected = 2 }, + { .mask = {.bits = 1 | 1 << 2 | 1 << 3}, + .expected = 3 }, + { .mask = {.bits = 1 | 1 << 3}, + .expected = 3 }, + { .mask = {.bits = 1 | 1 << 22}, + .expected = 22 }, + { .mask = {.bits = 1 | 1 << 10 | 1 << 16 | 1 << 22}, + .expected = 22 }, + }; + for (uint8_t n = 0; n < sizeof(test) / sizeof(test[0]); n++) + { + uint8_t l = TALER_adult_age (&test[n].mask); + printf ("adult[%d] for mask %s, expected: %d, got: %d\n", + n, TALER_age_mask_to_string (&test[n].mask), test[n].expected, l); + if (test[n].expected != l) + return GNUNET_SYSERR; + } + printf ("done with adult\n"); + + return GNUNET_OK; +} + + static struct TALER_AgeMask age_mask = { .bits = 1 | 1 << 8 | 1 << 10 | 1 << 12 | 1 << 14 | 1 << 16 | 1 << 18 | 1 << 21 }; @@ -146,7 +313,7 @@ test_attestation (void) enum GNUNET_GenericReturnValue ret; struct TALER_AgeCommitmentProof acp[3] = {0}; struct TALER_AgeAttestation at = {0}; - uint8_t age_group = get_age_group (&age_mask, age); + uint8_t age_group = TALER_get_age_group (&age_mask, age); struct GNUNET_HashCode seed; @@ -154,15 +321,13 @@ test_attestation (void) &seed, sizeof(seed)); - ret = TALER_age_restriction_commit (&age_mask, - age, - &seed, - &acp[0]); - + TALER_age_restriction_commit (&age_mask, + age, + &seed, + &acp[0]); printf ( - "commit(age:%d) == %d; proof.num: %ld; age_group: %d\n", + "commit(age:%d); proof.num: %ld; age_group: %d\n", age, - ret, acp[0].proof.num, age_group); @@ -183,7 +348,7 @@ test_attestation (void) { for (uint8_t min = 0; min < 22; min++) { - uint8_t min_group = get_age_group (&age_mask, min); + uint8_t min_group = TALER_get_age_group (&age_mask, min); ret = TALER_age_commitment_attest (&acp[i], min, @@ -259,11 +424,17 @@ main (int argc, NULL); if (GNUNET_OK != test_groups ()) return 1; + if (GNUNET_OK != test_lowest ()) + return 2; if (GNUNET_OK != test_attestation ()) { GNUNET_break (0); - return 2; + return 3; } + if (GNUNET_OK != test_dates ()) + return 4; + if (GNUNET_OK != test_adult ()) + return 5; return 0; } diff --git a/src/util/test_amount.c b/src/util/test_amount.c index c94f24fe5..57d73b14f 100644 --- a/src/util/test_amount.c +++ b/src/util/test_amount.c @@ -78,31 +78,31 @@ main (int argc, /* test conversion with leading zero in fraction */ GNUNET_assert (GNUNET_OK == - TALER_string_to_amount ("eur:0.02", + TALER_string_to_amount ("EUR:0.02", &a2)); - GNUNET_assert (0 == strcasecmp ("eur", + GNUNET_assert (0 == strcasecmp ("EUR", a2.currency)); GNUNET_assert (0 == a2.value); GNUNET_assert (TALER_AMOUNT_FRAC_BASE / 100 * 2 == a2.fraction); c = TALER_amount_to_string (&a2); - GNUNET_assert (0 == strcmp ("eur:0.02", - c)); + GNUNET_assert (0 == strcasecmp ("EUR:0.02", + c)); GNUNET_free (c); /* test conversion with leading space and with fraction */ GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (" eur:4.12", + TALER_string_to_amount (" EUR:4.12", &a2)); - GNUNET_assert (0 == strcasecmp ("eur", + GNUNET_assert (0 == strcasecmp ("EUR", a2.currency)); GNUNET_assert (4 == a2.value); GNUNET_assert (TALER_AMOUNT_FRAC_BASE / 100 * 12 == a2.fraction); /* test use of local currency */ GNUNET_assert (GNUNET_OK == - TALER_string_to_amount (" *LOCAL:4444.1000", + TALER_string_to_amount (" LOCAL:4444.1000", &a3)); - GNUNET_assert (0 == strcasecmp ("*LOCAL", + GNUNET_assert (0 == strcasecmp ("LOCAL", a3.currency)); GNUNET_assert (4444 == a3.value); GNUNET_assert (TALER_AMOUNT_FRAC_BASE / 10 == a3.fraction); diff --git a/src/util/test_conversion.c b/src/util/test_conversion.c new file mode 100644 index 000000000..00cb35e72 --- /dev/null +++ b/src/util/test_conversion.c @@ -0,0 +1,149 @@ +/* + This file is part of TALER + (C) 2023 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 util/test_conversion.c + * @brief Tests for conversion logic + * @author Christian Grothoff + */ +#include "platform.h" +#include "taler_util.h" +#include <gnunet/gnunet_json_lib.h> + +/** + * Return value from main(). + */ +static int global_ret; + +/** + * Handle to our helper. + */ +static struct TALER_JSON_ExternalConversion *ec; + + +/** + * Type of a callback that receives a JSON @a result. + * + * @param cls closure + * @param status_type how did the process die + * @apram code termination status code from the process + * @param result some JSON result, NULL if we failed to get an JSON output + */ +static void +conv_cb (void *cls, + enum GNUNET_OS_ProcessStatusType status_type, + unsigned long code, + const json_t *result) +{ + json_t *expect; + + (void) cls; + (void) status_type; + ec = NULL; + global_ret = 3; + if (42 != code) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected return value from helper: %u\n", + (unsigned int) code); + return; + } + expect = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("foo", + "arg") + ); + if (1 == json_equal (expect, + result)) + { + global_ret = 0; + } + else + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Unexpected JSON result\n"); + json_dumpf (result, + stderr, + JSON_INDENT (2)); + global_ret = 4; + } + json_decref (expect); +} + + +/** + * Function called on shutdown/CTRL-C. + * + * @param cls NULL + */ +static void +do_shutdown (void *cls) +{ + (void) cls; + if (NULL != ec) + { + GNUNET_break (0); + global_ret = 2; + TALER_JSON_external_conversion_stop (ec); + ec = NULL; + } +} + + +/** + * Main test function. + * + * @param cls NULL + */ +static void +run (void *cls) +{ + json_t *input; + + (void) cls; + GNUNET_SCHEDULER_add_shutdown (&do_shutdown, + NULL); + input = GNUNET_JSON_PACK ( + GNUNET_JSON_pack_string ("key", + "foo") + ); + ec = TALER_JSON_external_conversion_start (input, + &conv_cb, + NULL, + "./test_conversion.sh", + "test_conversion.sh", + "arg", + NULL); + json_decref (input); + GNUNET_assert (NULL != ec); +} + + +int +main (int argc, + const char *const argv[]) +{ + (void) argc; + (void) argv; + unsetenv ("XDG_DATA_HOME"); + unsetenv ("XDG_CONFIG_HOME"); + GNUNET_log_setup ("test-conversion", + "WARNING", + NULL); + GNUNET_OS_init (TALER_project_data_default ()); + global_ret = 1; + GNUNET_SCHEDULER_run (&run, + NULL); + return global_ret; +} diff --git a/src/util/test_conversion.sh b/src/util/test_conversion.sh new file mode 100755 index 000000000..26e1a36d8 --- /dev/null +++ b/src/util/test_conversion.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +KEY=$(jq -r .key) +echo -n "{\"$KEY\":\"$1\"}" +exit 42 diff --git a/src/util/test_crypto.c b/src/util/test_crypto.c index 80a247770..2a2090952 100644 --- a/src/util/test_crypto.c +++ b/src/util/test_crypto.c @@ -1,6 +1,6 @@ /* This file is part of TALER - (C) 2015, 2020-2022 Taler Systems SA + (C) 2015, 2020-2023 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 @@ -37,14 +37,21 @@ test_high_level (void) struct TALER_TransferPublicKeyP trans_pub; struct TALER_TransferSecretP secret; struct TALER_TransferSecretP secret2; - union TALER_DenominationBlindingKeyP bks1; - union TALER_DenominationBlindingKeyP bks2; + union GNUNET_CRYPTO_BlindingSecretP bks1; + union GNUNET_CRYPTO_BlindingSecretP bks2; struct TALER_CoinSpendPrivateKeyP coin_priv1; struct TALER_CoinSpendPrivateKeyP coin_priv2; struct TALER_PlanchetMasterSecretP ps1; struct TALER_PlanchetMasterSecretP ps2; - struct TALER_ExchangeWithdrawValues alg1; - struct TALER_ExchangeWithdrawValues alg2; + struct GNUNET_CRYPTO_BlindingInputValues bi = { + .cipher = GNUNET_CRYPTO_BSA_RSA + }; + struct TALER_ExchangeWithdrawValues alg1 = { + .blinding_inputs = &bi + }; + struct TALER_ExchangeWithdrawValues alg2 = { + .blinding_inputs = &bi + }; GNUNET_CRYPTO_eddsa_key_create (&coin_priv.eddsa_priv); GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv.eddsa_priv, @@ -70,14 +77,12 @@ test_high_level (void) TALER_transfer_secret_to_planchet_secret (&secret, 0, &ps1); - alg1.cipher = TALER_DENOMINATION_RSA; TALER_planchet_setup_coin_priv (&ps1, &alg1, &coin_priv1); TALER_planchet_blinding_secret_create (&ps1, &alg1, &bks1); - alg2.cipher = TALER_DENOMINATION_RSA; TALER_transfer_secret_to_planchet_secret (&secret, 1, &ps2); @@ -116,10 +121,10 @@ test_planchets_rsa (uint8_t age) { struct TALER_PlanchetMasterSecretP ps; struct TALER_CoinSpendPrivateKeyP coin_priv; - union TALER_DenominationBlindingKeyP bks; + union GNUNET_CRYPTO_BlindingSecretP bks; struct TALER_DenominationPrivateKey dk_priv; struct TALER_DenominationPublicKey dk_pub; - struct TALER_ExchangeWithdrawValues alg_values; + const struct TALER_ExchangeWithdrawValues *alg_values; struct TALER_PlanchetDetail pd; struct TALER_BlindedDenominationSignature blind_sig; struct TALER_FreshCoin coin; @@ -127,6 +132,7 @@ test_planchets_rsa (uint8_t age) struct TALER_AgeCommitmentHash *ach = NULL; struct TALER_AgeCommitmentHash ah = {0}; + alg_values = TALER_denom_ewv_rsa_singleton (); if (0 < age) { struct TALER_AgeCommitmentProof acp; @@ -135,12 +141,10 @@ test_planchets_rsa (uint8_t age) GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, &seed, sizeof(seed)); - - GNUNET_assert (GNUNET_OK == - TALER_age_restriction_commit (&age_mask, - age, - &seed, - &acp)); + TALER_age_restriction_commit (&age_mask, + age, + &seed, + &acp); TALER_age_commitment_hash (&acp.commitment, &ah); ach = &ah; @@ -154,7 +158,7 @@ test_planchets_rsa (uint8_t age) GNUNET_assert (GNUNET_SYSERR == TALER_denom_priv_create (&dk_priv, &dk_pub, - TALER_DENOMINATION_INVALID)); + GNUNET_CRYPTO_BSA_INVALID)); GNUNET_log_skip (1, GNUNET_YES); GNUNET_assert (GNUNET_SYSERR == TALER_denom_priv_create (&dk_priv, @@ -164,19 +168,19 @@ test_planchets_rsa (uint8_t age) GNUNET_assert (GNUNET_OK == TALER_denom_priv_create (&dk_priv, &dk_pub, - TALER_DENOMINATION_RSA, + GNUNET_CRYPTO_BSA_RSA, 1024)); - alg_values.cipher = TALER_DENOMINATION_RSA; TALER_planchet_setup_coin_priv (&ps, - &alg_values, + alg_values, &coin_priv); TALER_planchet_blinding_secret_create (&ps, - &alg_values, + alg_values, &bks); GNUNET_assert (GNUNET_OK == TALER_planchet_prepare (&dk_pub, - &alg_values, + alg_values, &bks, + NULL, &coin_priv, ach, &c_hash, @@ -194,7 +198,7 @@ test_planchets_rsa (uint8_t age) &coin_priv, ach, &c_hash, - &alg_values, + alg_values, &coin)); TALER_blinded_denom_sig_free (&blind_sig); TALER_denom_sig_free (&coin.sig); @@ -205,39 +209,6 @@ test_planchets_rsa (uint8_t age) /** - * @brief Function for CS signatures to derive public R_0 and R_1 - * - * @param nonce withdraw nonce from a client - * @param denom_priv denomination privkey as long-term secret - * @param r_pub the resulting R_0 and R_1 - * @return enum GNUNET_GenericReturnValue - */ -static enum GNUNET_GenericReturnValue -derive_r_public ( - const struct TALER_CsNonce *nonce, - const struct TALER_DenominationPrivateKey *denom_priv, - struct TALER_DenominationCSPublicRPairP *r_pub) -{ - struct GNUNET_CRYPTO_CsRSecret r[2]; - - if (denom_priv->cipher != TALER_DENOMINATION_CS) - { - GNUNET_break (0); - return GNUNET_SYSERR; - } - GNUNET_CRYPTO_cs_r_derive (&nonce->nonce, - "rw", - &denom_priv->details.cs_private_key, - r); - GNUNET_CRYPTO_cs_r_get_public (&r[0], - &r_pub->r_pub[0]); - GNUNET_CRYPTO_cs_r_get_public (&r[1], - &r_pub->r_pub[1]); - return GNUNET_OK; -} - - -/** * Test the basic planchet functionality of creating a fresh planchet with CS denomination * and extracting the respective signature. * @@ -248,11 +219,12 @@ test_planchets_cs (uint8_t age) { struct TALER_PlanchetMasterSecretP ps; struct TALER_CoinSpendPrivateKeyP coin_priv; - union TALER_DenominationBlindingKeyP bks; + union GNUNET_CRYPTO_BlindingSecretP bks; struct TALER_DenominationPrivateKey dk_priv; struct TALER_DenominationPublicKey dk_pub; struct TALER_PlanchetDetail pd; struct TALER_CoinPubHashP c_hash; + union GNUNET_CRYPTO_BlindSessionNonce nonce; struct TALER_BlindedDenominationSignature blind_sig; struct TALER_FreshCoin coin; struct TALER_ExchangeWithdrawValues alg_values; @@ -267,12 +239,10 @@ test_planchets_cs (uint8_t age) GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, &seed, sizeof(seed)); - - GNUNET_assert (GNUNET_OK == - TALER_age_restriction_commit (&age_mask, - age, - &seed, - &acp)); + TALER_age_restriction_commit (&age_mask, + age, + &seed, + &acp); TALER_age_commitment_hash (&acp.commitment, &ah); ach = &ah; @@ -285,16 +255,17 @@ test_planchets_cs (uint8_t age) GNUNET_assert (GNUNET_OK == TALER_denom_priv_create (&dk_priv, &dk_pub, - TALER_DENOMINATION_CS)); - alg_values.cipher = TALER_DENOMINATION_CS; + GNUNET_CRYPTO_BSA_CS)); TALER_cs_withdraw_nonce_derive ( &ps, - &pd.blinded_planchet.details.cs_blinded_planchet.nonce); - GNUNET_assert (GNUNET_OK == - derive_r_public ( - &pd.blinded_planchet.details.cs_blinded_planchet.nonce, - &dk_priv, - &alg_values.details.cs_values)); + &nonce.cs_nonce); + // FIXME: define Taler abstraction for this: + alg_values.blinding_inputs + = GNUNET_CRYPTO_get_blinding_input_values (dk_priv.bsign_priv_key, + &nonce, + "rw"); + TALER_denom_pub_hash (&dk_pub, + &pd.denom_pub_hash); TALER_planchet_setup_coin_priv (&ps, &alg_values, &coin_priv); @@ -305,6 +276,7 @@ test_planchets_cs (uint8_t age) TALER_planchet_prepare (&dk_pub, &alg_values, &bks, + &nonce, &coin_priv, ach, &c_hash, @@ -314,7 +286,6 @@ test_planchets_cs (uint8_t age) &dk_priv, false, &pd.blinded_planchet)); - TALER_planchet_detail_free (&pd); GNUNET_assert (GNUNET_OK == TALER_planchet_to_coin (&dk_pub, &blind_sig, @@ -355,15 +326,24 @@ test_exchange_sigs (void) struct TALER_MasterPrivateKeyP priv; struct TALER_MasterPublicKeyP pub; struct TALER_MasterSignatureP sig; + json_t *rest; GNUNET_CRYPTO_eddsa_key_create (&priv.eddsa_priv); + rest = json_array (); + GNUNET_assert (NULL != rest); TALER_exchange_wire_signature_make (pt, + NULL, + rest, + rest, &priv, &sig); GNUNET_CRYPTO_eddsa_key_get_public (&priv.eddsa_priv, &pub.eddsa_pub); if (GNUNET_OK != TALER_exchange_wire_signature_check (pt, + NULL, + rest, + rest, &pub, &sig)) { @@ -373,12 +353,28 @@ test_exchange_sigs (void) if (GNUNET_OK == TALER_exchange_wire_signature_check ( "payto://x-taler-bank/localhost/Other", + NULL, + rest, + rest, + &pub, + &sig)) + { + GNUNET_break (0); + return 1; + } + if (GNUNET_OK == + TALER_exchange_wire_signature_check ( + pt, + "http://example.com/", + rest, + rest, &pub, &sig)) { GNUNET_break (0); return 1; } + json_decref (rest); return 0; } diff --git a/src/util/test_helper_cs.c b/src/util/test_helper_cs.c index 2dada0e19..93562e459 100644 --- a/src/util/test_helper_cs.c +++ b/src/util/test_helper_cs.c @@ -1,6 +1,6 @@ /* This file is part of TALER - (C) 2020, 2021 Taler Systems SA + (C) 2020, 2021, 2023 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 @@ -129,7 +129,7 @@ free_keys (void) * @param validity_duration how long does the key remain available for signing; * zero if the key has been revoked or purged * @param h_cs hash of the @a denom_pub that is available (or was purged) - * @param denom_pub the public key itself, NULL if the key was revoked or purged + * @param bs_pub the public key itself, NULL if the key was revoked or purged * @param sm_pub public key of the security module, NULL if the key was revoked or purged * @param sm_sig signature from the security module, NULL if the key was revoked or purged * The signature was already verified against @a sm_pub. @@ -140,7 +140,7 @@ key_cb (void *cls, struct GNUNET_TIME_Timestamp start_time, struct GNUNET_TIME_Relative validity_duration, const struct TALER_CsPubHashP *h_cs, - const struct TALER_DenominationPublicKey *denom_pub, + struct GNUNET_CRYPTO_BlindSignPublicKey *bs_pub, const struct TALER_SecurityModulePublicKeyP *sm_pub, const struct TALER_SecurityModuleSignatureP *sm_sig) { @@ -155,7 +155,7 @@ key_cb (void *cls, { bool found = false; - GNUNET_break (NULL == denom_pub); + GNUNET_break (NULL == bs_pub); GNUNET_break (NULL == section_name); for (unsigned int i = 0; i<MAX_KEYS; i++) if (0 == GNUNET_memcmp (h_cs, @@ -176,7 +176,7 @@ key_cb (void *cls, return; } - GNUNET_break (NULL != denom_pub); + GNUNET_break (NULL != bs_pub); for (unsigned int i = 0; i<MAX_KEYS; i++) if (! keys[i].valid) { @@ -184,8 +184,8 @@ key_cb (void *cls, keys[i].h_cs = *h_cs; keys[i].start_time = start_time; keys[i].validity_duration = validity_duration; - TALER_denom_pub_deep_copy (&keys[i].denom_pub, - denom_pub); + keys[i].denom_pub.bsign_pub_key + = GNUNET_CRYPTO_bsign_pub_incref (bs_pub); num_keys++; return; } @@ -268,9 +268,15 @@ test_r_derive (struct TALER_CRYPTO_CsDenominationHelper *dh) bool success = false; struct TALER_PlanchetMasterSecretP ps; struct TALER_CoinSpendPrivateKeyP coin_priv; - union TALER_DenominationBlindingKeyP bks; + union GNUNET_CRYPTO_BlindingSecretP bks; struct TALER_CoinPubHashP c_hash; - struct TALER_ExchangeWithdrawValues alg_values; + struct GNUNET_CRYPTO_BlindingInputValues bi = { + .cipher = GNUNET_CRYPTO_BSA_CS + }; + struct TALER_ExchangeWithdrawValues alg_values = { + .blinding_inputs = &bi + }; + union GNUNET_CRYPTO_BlindSessionNonce nonce; TALER_planchet_master_setup_random (&ps); for (unsigned int i = 0; i<MAX_KEYS; i++) @@ -279,27 +285,25 @@ test_r_derive (struct TALER_CRYPTO_CsDenominationHelper *dh) if (! keys[i].valid) continue; - GNUNET_assert (TALER_DENOMINATION_CS == - keys[i].denom_pub.cipher); - pd.blinded_planchet.cipher = TALER_DENOMINATION_CS; + GNUNET_assert (GNUNET_CRYPTO_BSA_CS == + keys[i].denom_pub.bsign_pub_key->cipher); TALER_cs_withdraw_nonce_derive ( &ps, - &pd.blinded_planchet.details.cs_blinded_planchet.nonce); + &nonce.cs_nonce); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Requesting R derivation with key %s\n", GNUNET_h2s (&keys[i].h_cs.hash)); - alg_values.cipher = TALER_DENOMINATION_CS; { struct TALER_CRYPTO_CsDeriveRequest cdr = { .h_cs = &keys[i].h_cs, - .nonce = &pd.blinded_planchet.details.cs_blinded_planchet.nonce + .nonce = &nonce.cs_nonce }; ec = TALER_CRYPTO_helper_cs_r_derive ( dh, &cdr, false, - &alg_values.details.cs_values); + &bi.details.cs_values); } switch (ec) { @@ -336,10 +340,12 @@ test_r_derive (struct TALER_CRYPTO_CsDenominationHelper *dh) TALER_planchet_prepare (&keys[i].denom_pub, &alg_values, &bks, + &nonce, &coin_priv, NULL, /* no age commitment */ &c_hash, &pd)); + TALER_blinded_planchet_free (&pd.blinded_planchet); GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Successfully prepared planchet"); success = true; @@ -379,11 +385,10 @@ test_r_derive (struct TALER_CRYPTO_CsDenominationHelper *dh) /* check R derivation does not work if the key is unknown */ { struct TALER_CsPubHashP rnd; - struct TALER_CsNonce nonce; - struct TALER_DenominationCSPublicRPairP crp; + struct GNUNET_CRYPTO_CSPublicRPairP crp; struct TALER_CRYPTO_CsDeriveRequest cdr = { .h_cs = &rnd, - .nonce = &nonce, + .nonce = &nonce.cs_nonce, }; GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, @@ -423,9 +428,15 @@ test_signing (struct TALER_CRYPTO_CsDenominationHelper *dh) bool success = false; struct TALER_PlanchetMasterSecretP ps; struct TALER_CoinSpendPrivateKeyP coin_priv; - union TALER_DenominationBlindingKeyP bks; + union GNUNET_CRYPTO_BlindingSecretP bks; struct TALER_CoinPubHashP c_hash; - struct TALER_ExchangeWithdrawValues alg_values; + struct GNUNET_CRYPTO_BlindingInputValues bi = { + .cipher = GNUNET_CRYPTO_BSA_CS + }; + struct TALER_ExchangeWithdrawValues alg_values = { + .blinding_inputs = &bi + }; + union GNUNET_CRYPTO_BlindSessionNonce nonce; TALER_planchet_master_setup_random (&ps); for (unsigned int i = 0; i<MAX_KEYS; i++) @@ -437,19 +448,16 @@ test_signing (struct TALER_CRYPTO_CsDenominationHelper *dh) struct TALER_CRYPTO_CsSignRequest csr; struct TALER_CRYPTO_CsDeriveRequest cdr = { .h_cs = &keys[i].h_cs, - .nonce = &pd.blinded_planchet.details.cs_blinded_planchet.nonce + .nonce = &nonce.cs_nonce }; - pd.blinded_planchet.cipher = TALER_DENOMINATION_CS; TALER_cs_withdraw_nonce_derive (&ps, - &pd.blinded_planchet.details. - cs_blinded_planchet.nonce); - alg_values.cipher = TALER_DENOMINATION_CS; + &nonce.cs_nonce); ec = TALER_CRYPTO_helper_cs_r_derive ( dh, &cdr, false, - &alg_values.details.cs_values); + &bi.details.cs_values); if (TALER_EC_NONE != ec) continue; TALER_planchet_setup_coin_priv (&ps, @@ -458,11 +466,11 @@ test_signing (struct TALER_CRYPTO_CsDenominationHelper *dh) TALER_planchet_blinding_secret_create (&ps, &alg_values, &bks); - GNUNET_assert (GNUNET_YES == TALER_planchet_prepare (&keys[i].denom_pub, &alg_values, &bks, + &nonce, &coin_priv, NULL, /* no age commitment */ &c_hash, @@ -472,12 +480,13 @@ test_signing (struct TALER_CRYPTO_CsDenominationHelper *dh) GNUNET_h2s (&keys[i].h_cs.hash)); csr.h_cs = &keys[i].h_cs; csr.blinded_planchet - = &pd.blinded_planchet.details.cs_blinded_planchet; + = &pd.blinded_planchet.blinded_message->details.cs_blinded_message; ec = TALER_CRYPTO_helper_cs_sign ( dh, &csr, false, &ds); + TALER_blinded_planchet_free (&pd.blinded_planchet); } switch (ec) { @@ -489,6 +498,7 @@ test_signing (struct TALER_CRYPTO_CsDenominationHelper *dh) { /* key worked too early */ GNUNET_break (0); + TALER_blinded_denom_sig_free (&ds); return 4; } if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_duration ( @@ -498,6 +508,7 @@ test_signing (struct TALER_CRYPTO_CsDenominationHelper *dh) { /* key worked too later */ GNUNET_break (0); + TALER_blinded_denom_sig_free (&ds); return 5; } { @@ -514,8 +525,11 @@ test_signing (struct TALER_CRYPTO_CsDenominationHelper *dh) &coin)) { GNUNET_break (0); + TALER_blinded_denom_sig_free (&ds); return 6; } + TALER_blinded_denom_sig_free (&ds); + TALER_denom_sig_free (&coin.sig); } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received valid signature for key %s\n", @@ -563,23 +577,24 @@ test_signing (struct TALER_CRYPTO_CsDenominationHelper *dh) GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, &rnd, sizeof (rnd)); - pd.blinded_planchet.cipher = TALER_DENOMINATION_CS; GNUNET_assert (GNUNET_YES == TALER_planchet_prepare (&keys[0].denom_pub, &alg_values, &bks, + &nonce, &coin_priv, NULL, /* no age commitment */ &c_hash, &pd)); csr.h_cs = &rnd; csr.blinded_planchet - = &pd.blinded_planchet.details.cs_blinded_planchet; + = &pd.blinded_planchet.blinded_message->details.cs_blinded_message; ec = TALER_CRYPTO_helper_cs_sign ( dh, &csr, false, &ds); + TALER_blinded_planchet_free (&pd.blinded_planchet); if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec) { if (TALER_EC_NONE == ec) @@ -613,9 +628,11 @@ test_batch_signing (struct TALER_CRYPTO_CsDenominationHelper *dh, bool success = false; struct TALER_PlanchetMasterSecretP ps[batch_size]; struct TALER_CoinSpendPrivateKeyP coin_priv[batch_size]; - union TALER_DenominationBlindingKeyP bks[batch_size]; + union GNUNET_CRYPTO_BlindingSecretP bks[batch_size]; struct TALER_CoinPubHashP c_hash[batch_size]; + struct GNUNET_CRYPTO_BlindingInputValues bi[batch_size]; struct TALER_ExchangeWithdrawValues alg_values[batch_size]; + union GNUNET_CRYPTO_BlindSessionNonce nonces[batch_size]; for (unsigned int i = 0; i<batch_size; i++) TALER_planchet_master_setup_random (&ps[i]); @@ -627,30 +644,29 @@ test_batch_signing (struct TALER_CRYPTO_CsDenominationHelper *dh, struct TALER_PlanchetDetail pd[batch_size]; struct TALER_CRYPTO_CsSignRequest csr[batch_size]; struct TALER_CRYPTO_CsDeriveRequest cdr[batch_size]; - struct TALER_DenominationCSPublicRPairP crps[batch_size]; + struct GNUNET_CRYPTO_CSPublicRPairP crps[batch_size]; for (unsigned int i = 0; i<batch_size; i++) { cdr[i].h_cs = &keys[k].h_cs; - cdr[i].nonce = - &pd[i].blinded_planchet.details.cs_blinded_planchet.nonce; - pd[i].blinded_planchet.cipher = TALER_DENOMINATION_CS; + cdr[i].nonce = &nonces[i].cs_nonce; TALER_cs_withdraw_nonce_derive ( &ps[i], - &pd[i].blinded_planchet.details.cs_blinded_planchet.nonce); - alg_values[i].cipher = TALER_DENOMINATION_CS; + &nonces[i].cs_nonce); + bi[i].cipher = GNUNET_CRYPTO_BSA_CS; + alg_values[i].blinding_inputs = &bi[i]; } ec = TALER_CRYPTO_helper_cs_r_batch_derive ( dh, - cdr, batch_size, + cdr, false, crps); if (TALER_EC_NONE != ec) continue; for (unsigned int i = 0; i<batch_size; i++) { - alg_values[i].details.cs_values = crps[i]; + bi[i].details.cs_values = crps[i]; TALER_planchet_setup_coin_priv (&ps[i], &alg_values[i], &coin_priv[i]); @@ -661,6 +677,7 @@ test_batch_signing (struct TALER_CRYPTO_CsDenominationHelper *dh, TALER_planchet_prepare (&keys[k].denom_pub, &alg_values[i], &bks[i], + &nonces[i], &coin_priv[i], NULL, /* no age commitment */ &c_hash[i], @@ -670,14 +687,18 @@ test_batch_signing (struct TALER_CRYPTO_CsDenominationHelper *dh, GNUNET_h2s (&keys[k].h_cs.hash)); csr[i].h_cs = &keys[k].h_cs; csr[i].blinded_planchet - = &pd[i].blinded_planchet.details.cs_blinded_planchet; + = &pd[i].blinded_planchet.blinded_message->details.cs_blinded_message; } ec = TALER_CRYPTO_helper_cs_batch_sign ( dh, - csr, batch_size, + csr, false, ds); + for (unsigned int i = 0; i<batch_size; i++) + { + TALER_blinded_planchet_free (&pd[i].blinded_planchet); + } } switch (ec) { @@ -719,11 +740,18 @@ test_batch_signing (struct TALER_CRYPTO_CsDenominationHelper *dh, GNUNET_break (0); return 6; } + TALER_blinded_denom_sig_free (&ds[i]); + TALER_denom_sig_free (&coin.sig); } GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Received valid signature for key %s\n", GNUNET_h2s (&keys[k].h_cs.hash)); } + else + { + for (unsigned int i = 0; i<batch_size; i++) + TALER_blinded_denom_sig_free (&ds[i]); + } success = true; break; case TALER_EC_EXCHANGE_DENOMINATION_HELPER_TOO_EARLY: @@ -768,28 +796,29 @@ test_batch_signing (struct TALER_CRYPTO_CsDenominationHelper *dh, GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, &rnd, sizeof (rnd)); - pd.blinded_planchet.cipher = TALER_DENOMINATION_CS; GNUNET_assert (GNUNET_YES == TALER_planchet_prepare (&keys[0].denom_pub, &alg_values[0], &bks[0], + &nonces[0], &coin_priv[0], NULL, /* no age commitment */ &c_hash[0], &pd)); csr.h_cs = &rnd; csr.blinded_planchet - = &pd.blinded_planchet.details.cs_blinded_planchet; + = &pd.blinded_planchet.blinded_message->details.cs_blinded_message; ec = TALER_CRYPTO_helper_cs_batch_sign ( dh, - &csr, 1, + &csr, false, &ds[0]); + TALER_blinded_planchet_free (&pd.blinded_planchet); if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec) { if (TALER_EC_NONE == ec) - TALER_blinded_denom_sig_free (ds); + TALER_blinded_denom_sig_free (&ds[0]); GNUNET_break (0); return 17; } @@ -816,8 +845,13 @@ perf_signing (struct TALER_CRYPTO_CsDenominationHelper *dh, struct GNUNET_TIME_Relative duration; struct TALER_PlanchetMasterSecretP ps; struct TALER_CoinSpendPrivateKeyP coin_priv; - union TALER_DenominationBlindingKeyP bks; - struct TALER_ExchangeWithdrawValues alg_values; + union GNUNET_CRYPTO_BlindingSecretP bks; + struct GNUNET_CRYPTO_BlindingInputValues bv = { + .cipher = GNUNET_CRYPTO_BSA_CS + }; + struct TALER_ExchangeWithdrawValues alg_values = { + .blinding_inputs = &bv + }; TALER_planchet_master_setup_random (&ps); duration = GNUNET_TIME_UNIT_ZERO; @@ -841,21 +875,20 @@ perf_signing (struct TALER_CRYPTO_CsDenominationHelper *dh, { struct TALER_CoinPubHashP c_hash; struct TALER_PlanchetDetail pd; + union GNUNET_CRYPTO_BlindSessionNonce nonce; struct TALER_CRYPTO_CsDeriveRequest cdr = { .h_cs = &keys[i].h_cs, - .nonce = &pd.blinded_planchet.details.cs_blinded_planchet.nonce + .nonce = &nonce.cs_nonce }; - pd.blinded_planchet.cipher = TALER_DENOMINATION_CS; - TALER_cs_withdraw_nonce_derive (&ps, - &pd.blinded_planchet.details. - cs_blinded_planchet.nonce); - alg_values.cipher = TALER_DENOMINATION_CS; + TALER_cs_withdraw_nonce_derive ( + &ps, + &nonce.cs_nonce); ec = TALER_CRYPTO_helper_cs_r_derive ( dh, &cdr, true, - &alg_values.details.cs_values); + &bv.details.cs_values); if (TALER_EC_NONE != ec) continue; TALER_planchet_setup_coin_priv (&ps, @@ -868,6 +901,7 @@ perf_signing (struct TALER_CRYPTO_CsDenominationHelper *dh, TALER_planchet_prepare (&keys[i].denom_pub, &alg_values, &bks, + &nonce, &coin_priv, NULL, /* no age commitment */ &c_hash, @@ -881,7 +915,7 @@ perf_signing (struct TALER_CRYPTO_CsDenominationHelper *dh, csr.h_cs = &keys[i].h_cs; csr.blinded_planchet - = &pd.blinded_planchet.details.cs_blinded_planchet; + = &pd.blinded_planchet.blinded_message->details.cs_blinded_message; ec = TALER_CRYPTO_helper_cs_sign ( dh, &csr, @@ -897,9 +931,10 @@ perf_signing (struct TALER_CRYPTO_CsDenominationHelper *dh, if (NUM_SIGN_PERFS <= j) break; } + TALER_blinded_planchet_free (&pd.blinded_planchet); } - } /* for i */ - } /* for j */ + } /* for i */ + } /* for j */ fprintf (stderr, "%u (%s) signature operations took %s\n", (unsigned int) NUM_SIGN_PERFS, @@ -935,6 +970,7 @@ par_signing (struct GNUNET_CONFIGURATION_Handle *cfg) int ret; dh = TALER_CRYPTO_helper_cs_connect (cfg, + "taler-exchange", &key_cb, NULL); GNUNET_assert (NULL != dh); @@ -992,6 +1028,7 @@ run_test (void) nanosleep (&req, NULL); dh = TALER_CRYPTO_helper_cs_connect (cfg, + "taler-exchange", &key_cb, NULL); if (NULL != dh) diff --git a/src/util/test_helper_eddsa.c b/src/util/test_helper_eddsa.c index da1c51b46..0119e4278 100644 --- a/src/util/test_helper_eddsa.c +++ b/src/util/test_helper_eddsa.c @@ -365,6 +365,7 @@ par_signing (struct GNUNET_CONFIGURATION_Handle *cfg) int ret; esh = TALER_CRYPTO_helper_esign_connect (cfg, + "taler-exchange", &key_cb, NULL); if (NULL == esh) @@ -427,6 +428,7 @@ run_test (void) nanosleep (&req, NULL); esh = TALER_CRYPTO_helper_esign_connect (cfg, + "taler-exchange", &key_cb, NULL); if (NULL != esh) diff --git a/src/util/test_helper_rsa.c b/src/util/test_helper_rsa.c index 1c7cc5bfe..2bc15879f 100644 --- a/src/util/test_helper_rsa.c +++ b/src/util/test_helper_rsa.c @@ -129,7 +129,7 @@ free_keys (void) * @param validity_duration how long does the key remain available for signing; * zero if the key has been revoked or purged * @param h_rsa hash of the @a denom_pub that is available (or was purged) - * @param denom_pub the public key itself, NULL if the key was revoked or purged + * @param bs_pub the public key itself, NULL if the key was revoked or purged * @param sm_pub public key of the security module, NULL if the key was revoked or purged * @param sm_sig signature from the security module, NULL if the key was revoked or purged * The signature was already verified against @a sm_pub. @@ -140,7 +140,7 @@ key_cb (void *cls, struct GNUNET_TIME_Timestamp start_time, struct GNUNET_TIME_Relative validity_duration, const struct TALER_RsaPubHashP *h_rsa, - const struct TALER_DenominationPublicKey *denom_pub, + struct GNUNET_CRYPTO_BlindSignPublicKey *bs_pub, const struct TALER_SecurityModulePublicKeyP *sm_pub, const struct TALER_SecurityModuleSignatureP *sm_sig) { @@ -155,7 +155,7 @@ key_cb (void *cls, { bool found = false; - GNUNET_break (NULL == denom_pub); + GNUNET_break (NULL == bs_pub); GNUNET_break (NULL == section_name); for (unsigned int i = 0; i<MAX_KEYS; i++) if (0 == GNUNET_memcmp (h_rsa, @@ -176,7 +176,7 @@ key_cb (void *cls, return; } - GNUNET_break (NULL != denom_pub); + GNUNET_break (NULL != bs_pub); for (unsigned int i = 0; i<MAX_KEYS; i++) if (! keys[i].valid) { @@ -184,8 +184,8 @@ key_cb (void *cls, keys[i].h_rsa = *h_rsa; keys[i].start_time = start_time; keys[i].validity_duration = validity_duration; - TALER_denom_pub_deep_copy (&keys[i].denom_pub, - denom_pub); + keys[i].denom_pub.bsign_pub_key + = GNUNET_CRYPTO_bsign_pub_incref (bs_pub); num_keys++; return; } @@ -268,19 +268,22 @@ test_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh) enum TALER_ErrorCode ec; bool success = false; struct TALER_PlanchetMasterSecretP ps; - struct TALER_ExchangeWithdrawValues alg_values; + const struct TALER_ExchangeWithdrawValues *alg_values + = TALER_denom_ewv_rsa_singleton (); struct TALER_AgeCommitmentHash ach; struct TALER_CoinPubHashP c_hash; struct TALER_CoinSpendPrivateKeyP coin_priv; - union TALER_DenominationBlindingKeyP bks; + union GNUNET_CRYPTO_BlindingSecretP bks; GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, &ps, sizeof (ps)); - - alg_values.cipher = TALER_DENOMINATION_RSA; - TALER_planchet_setup_coin_priv (&ps, &alg_values, &coin_priv); - TALER_planchet_blinding_secret_create (&ps, &alg_values, &bks); + TALER_planchet_setup_coin_priv (&ps, + alg_values, + &coin_priv); + TALER_planchet_blinding_secret_create (&ps, + alg_values, + &bks); GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, &ach, sizeof(ach)); @@ -289,17 +292,17 @@ test_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh) { if (! keys[i].valid) continue; - if (TALER_DENOMINATION_RSA != keys[i].denom_pub.cipher) + if (GNUNET_CRYPTO_BSA_RSA != + keys[i].denom_pub.bsign_pub_key->cipher) continue; { - struct TALER_PlanchetDetail pd = { - .blinded_planchet.cipher = TALER_DENOMINATION_RSA - }; + struct TALER_PlanchetDetail pd; GNUNET_assert (GNUNET_YES == TALER_planchet_prepare (&keys[i].denom_pub, - &alg_values, + alg_values, &bks, + NULL, &coin_priv, &ach, &c_hash, @@ -308,9 +311,11 @@ test_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh) struct TALER_CRYPTO_RsaSignRequest rsr = { .h_rsa = &keys[i].h_rsa, .msg = - pd.blinded_planchet.details.rsa_blinded_planchet.blinded_msg, + pd.blinded_planchet.blinded_message->details.rsa_blinded_message. + blinded_msg, .msg_size = - pd.blinded_planchet.details.rsa_blinded_planchet.blinded_msg_size + pd.blinded_planchet.blinded_message->details.rsa_blinded_message. + blinded_msg_size }; GNUNET_log (GNUNET_ERROR_TYPE_INFO, @@ -352,7 +357,7 @@ test_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh) &ds, &bks, &c_hash, - &alg_values, + alg_values, &keys[i].denom_pub)) { GNUNET_break (0); @@ -457,11 +462,11 @@ test_batch_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh, enum TALER_ErrorCode ec; bool success = false; struct TALER_PlanchetMasterSecretP ps[batch_size]; - struct TALER_ExchangeWithdrawValues alg_values[batch_size]; + const struct TALER_ExchangeWithdrawValues *alg_values; struct TALER_AgeCommitmentHash ach[batch_size]; struct TALER_CoinPubHashP c_hash[batch_size]; struct TALER_CoinSpendPrivateKeyP coin_priv[batch_size]; - union TALER_DenominationBlindingKeyP bks[batch_size]; + union GNUNET_CRYPTO_BlindingSecretP bks[batch_size]; GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, &ps, @@ -469,14 +474,14 @@ test_batch_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh, GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, &ach, sizeof(ach)); + alg_values = TALER_denom_ewv_rsa_singleton (); for (unsigned int i = 0; i<batch_size; i++) { - alg_values[i].cipher = TALER_DENOMINATION_RSA; TALER_planchet_setup_coin_priv (&ps[i], - &alg_values[i], + alg_values, &coin_priv[i]); TALER_planchet_blinding_secret_create (&ps[i], - &alg_values[i], + alg_values, &bks[i]); } for (unsigned int k = 0; k<MAX_KEYS; k++) @@ -485,7 +490,8 @@ test_batch_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh, break; /* only do one round */ if (! keys[k].valid) continue; - if (TALER_DENOMINATION_RSA != keys[k].denom_pub.cipher) + if (GNUNET_CRYPTO_BSA_RSA != + keys[k].denom_pub.bsign_pub_key->cipher) continue; { struct TALER_PlanchetDetail pd[batch_size]; @@ -493,11 +499,11 @@ test_batch_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh, for (unsigned int i = 0; i<batch_size; i++) { - pd[i].blinded_planchet.cipher = TALER_DENOMINATION_RSA; GNUNET_assert (GNUNET_YES == TALER_planchet_prepare (&keys[k].denom_pub, - &alg_values[i], + alg_values, &bks[i], + NULL, &coin_priv[i], &ach[i], &c_hash[i], @@ -505,19 +511,21 @@ test_batch_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh, rsr[i].h_rsa = &keys[k].h_rsa; rsr[i].msg - = pd[i].blinded_planchet.details.rsa_blinded_planchet.blinded_msg; + = pd[i].blinded_planchet.blinded_message->details.rsa_blinded_message. + blinded_msg; rsr[i].msg_size - = pd[i].blinded_planchet.details.rsa_blinded_planchet.blinded_msg_size; + = pd[i].blinded_planchet.blinded_message->details.rsa_blinded_message. + blinded_msg_size; } ec = TALER_CRYPTO_helper_rsa_batch_sign (dh, - rsr, batch_size, + rsr, ds); for (unsigned int i = 0; i<batch_size; i++) { if (TALER_EC_NONE == ec) - GNUNET_break (TALER_DENOMINATION_RSA == - ds[i].cipher); + GNUNET_break (GNUNET_CRYPTO_BSA_RSA == + ds[i].blinded_sig->cipher); TALER_blinded_planchet_free (&pd[i].blinded_planchet); } } @@ -553,7 +561,7 @@ test_batch_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh, &ds[i], &bks[i], &c_hash[i], - &alg_values[i], + alg_values, &keys[k].denom_pub)) { GNUNET_break (0); @@ -637,8 +645,8 @@ test_batch_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh, &rnd, sizeof (rnd)); ec = TALER_CRYPTO_helper_rsa_batch_sign (dh, - &rsr, 1, + &rsr, ds); if (TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN != ec) { @@ -674,13 +682,17 @@ perf_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh, struct TALER_PlanchetMasterSecretP ps; struct TALER_CoinSpendPrivateKeyP coin_priv; struct TALER_AgeCommitmentHash ach; - union TALER_DenominationBlindingKeyP bks; - struct TALER_ExchangeWithdrawValues alg_values; + union GNUNET_CRYPTO_BlindingSecretP bks; + const struct TALER_ExchangeWithdrawValues *alg_values + = TALER_denom_ewv_rsa_singleton (); TALER_planchet_master_setup_random (&ps); - alg_values.cipher = TALER_DENOMINATION_RSA; - TALER_planchet_setup_coin_priv (&ps, &alg_values, &coin_priv); - TALER_planchet_blinding_secret_create (&ps, &alg_values, &bks); + TALER_planchet_setup_coin_priv (&ps, + alg_values, + &coin_priv); + TALER_planchet_blinding_secret_create (&ps, + alg_values, + &bks); GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, &ach, sizeof(ach)); @@ -692,7 +704,8 @@ perf_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh, { if (! keys[i].valid) continue; - if (TALER_DENOMINATION_RSA != keys[i].denom_pub.cipher) + if (GNUNET_CRYPTO_BSA_RSA != + keys[i].denom_pub.bsign_pub_key->cipher) continue; if (GNUNET_TIME_relative_cmp (GNUNET_TIME_absolute_get_remaining ( keys[i].start_time.abs_time), @@ -710,8 +723,9 @@ perf_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh, GNUNET_assert (GNUNET_YES == TALER_planchet_prepare (&keys[i].denom_pub, - &alg_values, + alg_values, &bks, + NULL, &coin_priv, &ach, &c_hash, @@ -724,9 +738,11 @@ perf_signing (struct TALER_CRYPTO_RsaDenominationHelper *dh, struct TALER_CRYPTO_RsaSignRequest rsr = { .h_rsa = &keys[i].h_rsa, .msg = - pd.blinded_planchet.details.rsa_blinded_planchet.blinded_msg, + pd.blinded_planchet.blinded_message->details.rsa_blinded_message. + blinded_msg, .msg_size = - pd.blinded_planchet.details.rsa_blinded_planchet.blinded_msg_size + pd.blinded_planchet.blinded_message->details.rsa_blinded_message. + blinded_msg_size }; ec = TALER_CRYPTO_helper_rsa_sign (dh, @@ -781,6 +797,7 @@ par_signing (struct GNUNET_CONFIGURATION_Handle *cfg) int ret; dh = TALER_CRYPTO_helper_rsa_connect (cfg, + "taler-exchange", &key_cb, NULL); GNUNET_assert (NULL != dh); @@ -839,6 +856,7 @@ run_test (void) nanosleep (&req, NULL); dh = TALER_CRYPTO_helper_rsa_connect (cfg, + "taler-exchange", &key_cb, NULL); if (NULL != dh) diff --git a/src/util/test_payto.c b/src/util/test_payto.c index 4dc73a964..62ba7d28e 100644 --- a/src/util/test_payto.c +++ b/src/util/test_payto.c @@ -22,16 +22,16 @@ #include "taler_util.h" #define CHECK(a,b) do { \ - GNUNET_assert (a != NULL); \ - GNUNET_assert (b != NULL); \ - if (0 != strcmp (a,b)) { \ - GNUNET_break (0); \ - fprintf (stderr, "Got %s, wanted %s\n", b, a); \ - GNUNET_free (b); \ - return 1; \ - } else { \ - GNUNET_free (b); \ - } \ + GNUNET_assert (a != NULL); \ + GNUNET_assert (b != NULL); \ + if (0 != strcmp (a,b)) { \ + GNUNET_break (0); \ + fprintf (stderr, "Got %s, wanted %s\n", b, a); \ + GNUNET_free (b); \ + return 1; \ + } else { \ + GNUNET_free (b); \ + } \ } while (0) @@ -50,11 +50,55 @@ main (int argc, TALER_iban_validate ("FR1420041010050500013M02606")); GNUNET_assert (NULL == TALER_iban_validate ("DE89370400440532013000")); + r = TALER_payto_validate ( + "payto://x-taler-bank/hostname/username?receiver-name=foo"); + GNUNET_assert (NULL == r); + r = TALER_payto_validate ( + "payto://x-taler-bank/hostname/~path/username?receiver-name=foo"); + GNUNET_assert (NULL == r); + r = TALER_payto_validate ( + "payto://x-taler-bank/hostname/~path/username?receiver-name=fo/o"); + GNUNET_assert (NULL == r); + r = TALER_payto_validate ( + "payto://x-taler-bank/hostname/path/username?receiver-name=foo"); + GNUNET_assert (NULL == r); + r = TALER_payto_validate ( + "payto://x-taler-bank/https://hostname/username?receiver-name=foo"); + GNUNET_assert (NULL != r); + GNUNET_free (r); + r = TALER_payto_validate ( + "payto://x-taler-bank/hostname:4a2/path/username?receiver-name=foo"); + GNUNET_assert (NULL != r); + GNUNET_free (r); + r = TALER_payto_validate ( + "payto://x-taler-bank/-hostname/username?receiver-name=foo"); + GNUNET_assert (NULL != r); + GNUNET_free (r); + r = TALER_payto_validate ( + "payto://x-taler-bank/domain..name/username?receiver-name=foo"); + GNUNET_assert (NULL != r); + GNUNET_free (r); + r = TALER_payto_validate ( + "payto://x-taler-bank/domain..name/?receiver-name=foo"); + GNUNET_assert (NULL != r); + GNUNET_free (r); + r = TALER_payto_validate ( + "payto://x-taler-bank/domain.name/username"); + GNUNET_assert (NULL != r); + GNUNET_free (r); r = TALER_xtalerbank_account_from_payto ( "payto://x-taler-bank/localhost:1080/alice"); CHECK ("alice", r); r = TALER_xtalerbank_account_from_payto ( + "payto://x-taler-bank/localhost:1080/path/alice"); + CHECK ("alice", + r); + r = TALER_xtalerbank_account_from_payto ( + "payto://x-taler-bank/localhost:1080/path/alice?receiver-name=ali/cia"); + CHECK ("alice", + r); + r = TALER_xtalerbank_account_from_payto ( "payto://x-taler-bank/localhost:1080/alice?subject=hello&amount=EUR:1"); CHECK ("alice", r); diff --git a/src/util/url.c b/src/util/url.c index a140a3a2e..bf59ba6ec 100644 --- a/src/util/url.c +++ b/src/util/url.c @@ -212,8 +212,6 @@ TALER_url_join (const char *base_url, ...) { struct GNUNET_Buffer buf = { 0 }; - va_list args; - size_t len; GNUNET_assert (NULL != base_url); GNUNET_assert (NULL != path); @@ -224,40 +222,45 @@ TALER_url_join (const char *base_url, "Empty base URL specified\n"); return NULL; } - if ('/' != base_url[strlen (base_url) - 1]) + if ('\0' != path[0]) { - /* Must be an actual base URL! */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Base URL `%s' does not end with '/', cannot join with `%s'\n", - base_url, - path); - return NULL; + if ('/' != base_url[strlen (base_url) - 1]) + { + /* Must be an actual base URL! */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Base URL `%s' does not end with '/', cannot join with `%s'\n", + base_url, + path); + return NULL; + } + if ('/' == path[0]) + { + /* The path must be relative. */ + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + "Path `%s' is not relative\n", + path); + return NULL; + } } - if ('/' == path[0]) + { - /* The path must be relative. */ - GNUNET_log (GNUNET_ERROR_TYPE_ERROR, - "Path `%s' is not relative\n", - path); - return NULL; + va_list args; + size_t len; + + va_start (args, + path); + len = strlen (base_url) + strlen (path) + 1; + len += calculate_argument_length (args); + GNUNET_buffer_prealloc (&buf, + len); + GNUNET_buffer_write_str (&buf, + base_url); + GNUNET_buffer_write_str (&buf, + path); + serialize_arguments (&buf, + args); + va_end (args); } - - va_start (args, - path); - - len = strlen (base_url) + strlen (path) + 1; - len += calculate_argument_length (args); - - GNUNET_buffer_prealloc (&buf, - len); - GNUNET_buffer_write_str (&buf, - base_url); - GNUNET_buffer_write_str (&buf, - path); - serialize_arguments (&buf, - args); - va_end (args); - return GNUNET_buffer_reap_str (&buf); } @@ -322,7 +325,7 @@ TALER_url_valid_charset (const char *url) for (unsigned int i = 0; '\0' != url[i]; i++) { #define ALLOWED_CHARACTERS \ - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/:;&?-.,=_~%+" + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789/:;&?-.,=_~%+#" if (NULL == strchr (ALLOWED_CHARACTERS, (int) url[i])) return false; @@ -332,4 +335,20 @@ TALER_url_valid_charset (const char *url) } +bool +TALER_is_web_url (const char *url) +{ + if ( (0 != strncasecmp (url, + "https://", + strlen ("https://"))) && + (0 != strncasecmp (url, + "http://", + strlen ("http://"))) ) + return false; + if (! TALER_url_valid_charset (url) ) + return false; + return true; +} + + /* end of url.c */ diff --git a/src/util/util.c b/src/util/util.c index 96d791912..da5727487 100644 --- a/src/util/util.c +++ b/src/util/util.c @@ -25,6 +25,7 @@ #include "taler_util.h" #include "taler_attributes.h" #include <gnunet/gnunet_json_lib.h> +#include <unistr.h> const char * @@ -40,9 +41,9 @@ TALER_b2s (const void *buf, &hc); tmp = GNUNET_STRINGS_data_to_string_alloc (&hc, sizeof (hc)); - memcpy (ret, - tmp, - 8); + GNUNET_memcpy (ret, + tmp, + 8); GNUNET_free (tmp); ret[8] = '\0'; return ret; @@ -205,6 +206,164 @@ TALER_denom_fee_check_currency ( /** + * Dump character in the low range into @a buf + * following RFC 8785. + * + * @param[in,out] buf buffer to modify + * @param val value to dump + */ +static void +lowdump (struct GNUNET_Buffer *buf, + unsigned char val) +{ + char scratch[7]; + + switch (val) + { + case 0x8: + GNUNET_buffer_write (buf, + "\\b", + 2); + break; + case 0x9: + GNUNET_buffer_write (buf, + "\\t", + 2); + break; + case 0xA: + GNUNET_buffer_write (buf, + "\\n", + 2); + break; + case 0xC: + GNUNET_buffer_write (buf, + "\\f", + 2); + break; + case 0xD: + GNUNET_buffer_write (buf, + "\\r", + 2); + break; + default: + GNUNET_snprintf (scratch, + sizeof (scratch), + "\\u%04x", + (unsigned int) val); + GNUNET_buffer_write (buf, + scratch, + 6); + break; + } +} + + +size_t +TALER_rfc8785encode (char **inp) +{ + struct GNUNET_Buffer buf = { 0 }; + size_t left = strlen (*inp) + 1; + size_t olen; + char *in = *inp; + const char *pos = in; + + GNUNET_buffer_prealloc (&buf, + left + 40); + buf.warn_grow = 0; /* disable, + 40 is just a wild guess */ + while (1) + { + int mbl = u8_mblen ((unsigned char *) pos, + left); + unsigned char val; + + if (0 == mbl) + break; + val = (unsigned char) *pos; + if ( (1 == mbl) && + (val <= 0x1F) ) + { + /* Should not happen, as input is produced by + * JSON stringification */ + GNUNET_break (0); + lowdump (&buf, + val); + } + else if ( (1 == mbl) && ('\\' == *pos) ) + { + switch (*(pos + 1)) + { + case '\\': + mbl = 2; + GNUNET_buffer_write (&buf, + pos, + mbl); + break; + case 'u': + { + unsigned int num; + uint32_t n32; + unsigned char res[8]; + size_t rlen; + + GNUNET_assert ( (1 == + sscanf (pos + 2, + "%4x", + &num)) || + (1 == + sscanf (pos + 2, + "%4X", + &num)) ); + mbl = 6; + n32 = (uint32_t) num; + rlen = sizeof (res); + u32_to_u8 (&n32, + 1, + res, + &rlen); + if ( (1 == rlen) && + (res[0] <= 0x1F) ) + { + lowdump (&buf, + res[0]); + } + else + { + GNUNET_buffer_write (&buf, + (const char *) res, + rlen); + } + } + break; + default: + mbl = 2; + GNUNET_buffer_write (&buf, + pos, + mbl); + break; + } + } + else + { + GNUNET_buffer_write (&buf, + pos, + mbl); + } + left -= mbl; + pos += mbl; + } + + /* 0-terminate buffer */ + GNUNET_buffer_write (&buf, + "", + 1); + GNUNET_free (in); + *inp = GNUNET_buffer_reap (&buf, + &olen); + return olen; +} + + +/** * Hash normalized @a j JSON object or array and * store the result in @a hc. * @@ -221,11 +380,11 @@ TALER_json_hash (const json_t *j, cstr = json_dumps (j, JSON_COMPACT | JSON_SORT_KEYS); GNUNET_assert (NULL != cstr); - clen = strlen (cstr); + clen = TALER_rfc8785encode (&cstr); GNUNET_CRYPTO_hash (cstr, clen, hc); - free (cstr); + GNUNET_free (cstr); } diff --git a/src/util/wallet_signatures.c b/src/util/wallet_signatures.c index 221865e73..0b6ab5432 100644 --- a/src/util/wallet_signatures.c +++ b/src/util/wallet_signatures.c @@ -1,6 +1,6 @@ /* This file is part of TALER - Copyright (C) 2021, 2022 Taler Systems SA + Copyright (C) 2021-2023 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 @@ -17,10 +17,12 @@ * @file wallet_signatures.c * @brief Utility functions for Taler wallet signatures * @author Christian Grothoff + * @author Özgür Kesim */ #include "platform.h" #include "taler_util.h" #include "taler_signatures.h" +#include <gnunet/gnunet_common.h> GNUNET_NETWORK_STRUCT_BEGIN @@ -109,6 +111,12 @@ struct TALER_DepositRequestPS */ struct TALER_MerchantPublicKeyP merchant; + /** + * Hash over a JSON containing data provided by the + * wallet to complete the contract upon payment. + */ + struct GNUNET_HashCode wallet_data_hash; + }; GNUNET_NETWORK_STRUCT_END @@ -119,6 +127,7 @@ TALER_wallet_deposit_sign ( const struct TALER_Amount *deposit_fee, const struct TALER_MerchantWireHashP *h_wire, const struct TALER_PrivateContractHashP *h_contract_terms, + const struct GNUNET_HashCode *wallet_data_hash, const struct TALER_AgeCommitmentHash *h_age_commitment, const struct TALER_ExtensionPolicyHashP *h_policy, const struct TALER_DenominationHashP *h_denom_pub, @@ -139,6 +148,8 @@ TALER_wallet_deposit_sign ( .merchant = *merchant_pub }; + if (NULL != wallet_data_hash) + dr.wallet_data_hash = *wallet_data_hash; if (NULL != h_age_commitment) dr.h_age_commitment = *h_age_commitment; if (NULL != h_policy) @@ -159,6 +170,7 @@ TALER_wallet_deposit_verify ( const struct TALER_Amount *deposit_fee, const struct TALER_MerchantWireHashP *h_wire, const struct TALER_PrivateContractHashP *h_contract_terms, + const struct GNUNET_HashCode *wallet_data_hash, const struct TALER_AgeCommitmentHash *h_age_commitment, const struct TALER_ExtensionPolicyHashP *h_policy, const struct TALER_DenominationHashP *h_denom_pub, @@ -177,10 +189,10 @@ TALER_wallet_deposit_verify ( .wallet_timestamp = GNUNET_TIME_timestamp_hton (wallet_timestamp), .refund_deadline = GNUNET_TIME_timestamp_hton (refund_deadline), .merchant = *merchant_pub, - .h_age_commitment = {{{0}}}, - .h_policy = {{{0}}} }; + if (NULL != wallet_data_hash) + dr.wallet_data_hash = *wallet_data_hash; if (NULL != h_age_commitment) dr.h_age_commitment = *h_age_commitment; if (NULL != h_policy) @@ -308,7 +320,7 @@ struct TALER_RecoupRequestPS /** * Blinding factor that was used to withdraw the coin. */ - union TALER_DenominationBlindingKeyP coin_blind; + union GNUNET_CRYPTO_BlindingSecretP coin_blind; }; @@ -318,7 +330,7 @@ GNUNET_NETWORK_STRUCT_END enum GNUNET_GenericReturnValue TALER_wallet_recoup_verify ( const struct TALER_DenominationHashP *h_denom_pub, - const union TALER_DenominationBlindingKeyP *coin_bks, + const union GNUNET_CRYPTO_BlindingSecretP *coin_bks, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_CoinSpendSignatureP *coin_sig) { @@ -339,7 +351,7 @@ TALER_wallet_recoup_verify ( void TALER_wallet_recoup_sign ( const struct TALER_DenominationHashP *h_denom_pub, - const union TALER_DenominationBlindingKeyP *coin_bks, + const union GNUNET_CRYPTO_BlindingSecretP *coin_bks, const struct TALER_CoinSpendPrivateKeyP *coin_priv, struct TALER_CoinSpendSignatureP *coin_sig) { @@ -359,7 +371,7 @@ TALER_wallet_recoup_sign ( enum GNUNET_GenericReturnValue TALER_wallet_recoup_refresh_verify ( const struct TALER_DenominationHashP *h_denom_pub, - const union TALER_DenominationBlindingKeyP *coin_bks, + const union GNUNET_CRYPTO_BlindingSecretP *coin_bks, const struct TALER_CoinSpendPublicKeyP *coin_pub, const struct TALER_CoinSpendSignatureP *coin_sig) { @@ -380,7 +392,7 @@ TALER_wallet_recoup_refresh_verify ( void TALER_wallet_recoup_refresh_sign ( const struct TALER_DenominationHashP *h_denom_pub, - const union TALER_DenominationBlindingKeyP *coin_bks, + const union GNUNET_CRYPTO_BlindingSecretP *coin_bks, const struct TALER_CoinSpendPrivateKeyP *coin_priv, struct TALER_CoinSpendSignatureP *coin_sig) { @@ -620,9 +632,9 @@ struct TALER_AgeWithdrawRequestPS struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** - * Hash of the commitment of n*kappa coins + * The reserve's public key */ - struct TALER_AgeWithdrawCommitmentHashP h_commitment GNUNET_PACKED; + struct TALER_ReservePublicKeyP reserve_pub; /** * Value of the coin being exchanged (matching the denomination key) @@ -634,9 +646,19 @@ struct TALER_AgeWithdrawRequestPS struct TALER_AmountNBO amount_with_fee; /** + * Running SHA512 hash of the commitment of n*kappa coins + */ + struct TALER_AgeWithdrawCommitmentHashP h_commitment; + + /** + * The mask that defines the age groups. MUST be the same for all denominations. + */ + struct TALER_AgeMask mask; + + /** * Maximum age group that the coins are going to be restricted to. */ - uint32_t max_age_group; + uint8_t max_age_group; }; @@ -646,7 +668,8 @@ void TALER_wallet_age_withdraw_sign ( const struct TALER_AgeWithdrawCommitmentHashP *h_commitment, const struct TALER_Amount *amount_with_fee, - uint32_t max_age_group, + const struct TALER_AgeMask *mask, + uint8_t max_age, const struct TALER_ReservePrivateKeyP *reserve_priv, struct TALER_ReserveSignatureP *reserve_sig) { @@ -654,9 +677,12 @@ TALER_wallet_age_withdraw_sign ( .purpose.size = htonl (sizeof (req)), .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_AGE_WITHDRAW), .h_commitment = *h_commitment, - .max_age_group = max_age_group + .mask = *mask, + .max_age_group = TALER_get_age_group (mask, max_age) }; + GNUNET_CRYPTO_eddsa_key_get_public (&reserve_priv->eddsa_priv, + &req.reserve_pub.eddsa_pub); TALER_amount_hton (&req.amount_with_fee, amount_with_fee); GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv, @@ -669,15 +695,18 @@ enum GNUNET_GenericReturnValue TALER_wallet_age_withdraw_verify ( const struct TALER_AgeWithdrawCommitmentHashP *h_commitment, const struct TALER_Amount *amount_with_fee, - uint32_t max_age_group, + const struct TALER_AgeMask *mask, + uint8_t max_age, const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReserveSignatureP *reserve_sig) { struct TALER_AgeWithdrawRequestPS awsrd = { .purpose.size = htonl (sizeof (awsrd)), .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_AGE_WITHDRAW), + .reserve_pub = *reserve_pub, .h_commitment = *h_commitment, - .max_age_group = max_age_group + .mask = *mask, + .max_age_group = TALER_get_age_group (mask, max_age) }; TALER_amount_hton (&awsrd.amount_with_fee, @@ -761,9 +790,7 @@ GNUNET_NETWORK_STRUCT_BEGIN /** - * Response by which a wallet requests a full - * reserve history and indicates it is willing - * to pay for it. + * Response by which a wallet requests a reserve history. */ struct TALER_ReserveHistoryRequestPS { @@ -774,36 +801,27 @@ struct TALER_ReserveHistoryRequestPS struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** - * When did the wallet make the request. - */ - struct GNUNET_TIME_TimestampNBO request_timestamp; - - /** - * How much does the exchange charge for the history? + * Which entries to exclude. Only return above this offset. */ - struct TALER_AmountNBO history_fee; + uint64_t start_off; }; - GNUNET_NETWORK_STRUCT_END enum GNUNET_GenericReturnValue TALER_wallet_reserve_history_verify ( - const struct GNUNET_TIME_Timestamp ts, - const struct TALER_Amount *history_fee, + uint64_t start_off, const struct TALER_ReservePublicKeyP *reserve_pub, const struct TALER_ReserveSignatureP *reserve_sig) { struct TALER_ReserveHistoryRequestPS rhr = { .purpose.size = htonl (sizeof (rhr)), .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_HISTORY), - .request_timestamp = GNUNET_TIME_timestamp_hton (ts) + .start_off = GNUNET_htonll (start_off) }; - TALER_amount_hton (&rhr.history_fee, - history_fee); return GNUNET_CRYPTO_eddsa_verify ( TALER_SIGNATURE_WALLET_RESERVE_HISTORY, &rhr, @@ -814,19 +832,16 @@ TALER_wallet_reserve_history_verify ( void TALER_wallet_reserve_history_sign ( - const struct GNUNET_TIME_Timestamp ts, - const struct TALER_Amount *history_fee, + uint64_t start_off, const struct TALER_ReservePrivateKeyP *reserve_priv, struct TALER_ReserveSignatureP *reserve_sig) { struct TALER_ReserveHistoryRequestPS rhr = { .purpose.size = htonl (sizeof (rhr)), .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_HISTORY), - .request_timestamp = GNUNET_TIME_timestamp_hton (ts) + .start_off = GNUNET_htonll (start_off) }; - TALER_amount_hton (&rhr.history_fee, - history_fee); GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv, &rhr, &reserve_sig->eddsa_signature); @@ -836,60 +851,60 @@ TALER_wallet_reserve_history_sign ( GNUNET_NETWORK_STRUCT_BEGIN /** - * Response by which a wallet requests an account status. + * Response by which a wallet requests a coin history. */ -struct TALER_ReserveStatusRequestPS +struct TALER_CoinHistoryRequestPS { /** - * Purpose is #TALER_SIGNATURE_WALLET_RESERVE_STATUS + * Purpose is #TALER_SIGNATURE_WALLET_COIN_HISTORY */ struct GNUNET_CRYPTO_EccSignaturePurpose purpose; /** - * When did the wallet make the request. + * Which entries to exclude. Only return above this offset. */ - struct GNUNET_TIME_TimestampNBO request_timestamp; + uint64_t start_off; }; GNUNET_NETWORK_STRUCT_END enum GNUNET_GenericReturnValue -TALER_wallet_reserve_status_verify ( - const struct GNUNET_TIME_Timestamp ts, - const struct TALER_ReservePublicKeyP *reserve_pub, - const struct TALER_ReserveSignatureP *reserve_sig) +TALER_wallet_coin_history_verify ( + uint64_t start_off, + const struct TALER_CoinSpendPublicKeyP *coin_pub, + const struct TALER_CoinSpendSignatureP *coin_sig) { - struct TALER_ReserveStatusRequestPS rsr = { + struct TALER_CoinHistoryRequestPS rsr = { .purpose.size = htonl (sizeof (rsr)), - .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_STATUS), - .request_timestamp = GNUNET_TIME_timestamp_hton (ts) + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_HISTORY), + .start_off = GNUNET_htonll (start_off) }; return GNUNET_CRYPTO_eddsa_verify ( - TALER_SIGNATURE_WALLET_RESERVE_STATUS, + TALER_SIGNATURE_WALLET_COIN_HISTORY, &rsr, - &reserve_sig->eddsa_signature, - &reserve_pub->eddsa_pub); + &coin_sig->eddsa_signature, + &coin_pub->eddsa_pub); } void -TALER_wallet_reserve_status_sign ( - const struct GNUNET_TIME_Timestamp ts, - const struct TALER_ReservePrivateKeyP *reserve_priv, - struct TALER_ReserveSignatureP *reserve_sig) +TALER_wallet_coin_history_sign ( + uint64_t start_off, + const struct TALER_CoinSpendPrivateKeyP *coin_priv, + struct TALER_CoinSpendSignatureP *coin_sig) { - struct TALER_ReserveStatusRequestPS rsr = { + struct TALER_CoinHistoryRequestPS rsr = { .purpose.size = htonl (sizeof (rsr)), - .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_RESERVE_STATUS), - .request_timestamp = GNUNET_TIME_timestamp_hton (ts) + .purpose.purpose = htonl (TALER_SIGNATURE_WALLET_COIN_HISTORY), + .start_off = GNUNET_htonll (start_off) }; - GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv, + GNUNET_CRYPTO_eddsa_sign (&coin_priv->eddsa_priv, &rsr, - &reserve_sig->eddsa_signature); + &coin_sig->eddsa_signature); } @@ -1528,6 +1543,7 @@ struct TALER_ReserveOpenDepositPS GNUNET_NETWORK_STRUCT_END +// FIXME-#7267: add h_age_commitment, h_denom_pub to have proof! void TALER_wallet_reserve_open_deposit_sign ( const struct TALER_Amount *coin_contribution, |