aboutsummaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/util')
-rw-r--r--src/util/age_restriction.c89
-rw-r--r--src/util/exchange_signatures.c28
-rw-r--r--src/util/test_age_restriction.c169
-rw-r--r--src/util/wallet_signatures.c35
4 files changed, 296 insertions, 25 deletions
diff --git a/src/util/age_restriction.c b/src/util/age_restriction.c
index f0d99fe66..6f0702298 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
@@ -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,6 +96,27 @@ 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
*
@@ -150,7 +172,7 @@ TALER_age_restriction_commit (
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);
@@ -335,8 +357,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);
@@ -386,8 +408,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);
@@ -604,7 +626,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);
@@ -689,4 +711,57 @@ TALER_age_restriction_from_secret (
}
+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-%0m-%0d", &date))
+ {
+ if (NULL == strptime (in, "%Y-%0m-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 = mktime (&date);
+ if (-1 == seconds)
+ return GNUNET_SYSERR;
+
+ /* calculate the limit date for the largest age group */
+ localtime_r (&(time_t){time (NULL)}, &limit);
+ limit.tm_year -= TALER_adult_age (mask);
+ GNUNET_assert (-1 != mktime (&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;
+}
+
+
/* end util/age_restriction.c */
diff --git a/src/util/exchange_signatures.c b/src/util/exchange_signatures.c
index 6f8ebdaff..3aa464aa7 100644
--- a/src/util/exchange_signatures.c
+++ b/src/util/exchange_signatures.c
@@ -413,6 +413,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 */
diff --git a/src/util/test_age_restriction.c b/src/util/test_age_restriction.c
index 77717616f..53cacc6d5 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"
@@ -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,153 @@ 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 = "2023-06-26", .expected = 19533, .ret = GNUNET_OK },
+ {.date = "2023-06-01", .expected = 19508, .ret = GNUNET_OK },
+ {.date = "2023-06-00", .expected = 19508, .ret = GNUNET_OK },
+ {.date = "2023-01-01", .expected = 19357, .ret = GNUNET_OK },
+ {.date = "2023-00-00", .expected = 19357, .ret = GNUNET_OK },
+ };
+
+ for (uint8_t t = 0; t < sizeof(test) / sizeof(test[0]); t++)
+ {
+ uint32_t d;
+ enum GNUNET_GenericReturnValue ret;
+
+ ret = TALER_parse_coarse_date (test[t].date,
+ &mask,
+ &d);
+ if (ret != test[t].ret)
+ {
+ printf (
+ "dates[%d] for date `%s` expected parser to return: %d, got: %d\n",
+ t, test[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, test[t].date, test[t].expected, d);
+ return GNUNET_SYSERR;
+ }
+
+ printf ("dates[%d] for date `%s` got expected value %d\n",
+ t, test[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 +289,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;
@@ -183,7 +326,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 +402,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/wallet_signatures.c b/src/util/wallet_signatures.c
index 221865e73..823641ed4 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
@@ -620,9 +622,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 +636,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 +658,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 +667,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 +685,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,