exchange

Base system with REST service to issue digital coins, run by the payment service provider
Log | Files | Refs | Submodules | README | LICENSE

test_exchange_sign_keys.c (8775B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2026 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
     12 
     13   You should have received a copy of the GNU General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file exchangedb/test_exchange_sign_keys.c
     18  * @brief tests for the exchangedb functions whose primary table is
     19  *        `exchange_sign_keys`
     20  * @author Christian Grothoff
     21  *
     22  * Covers #TALER_EXCHANGEDB_insert_signkey(),
     23  * #TALER_EXCHANGEDB_get_signkey() and
     24  * #TALER_EXCHANGEDB_iterate_active_signkeys().
     25  *
     26  * `exchange_sign_keys` has no foreign keys.  The interesting part is what
     27  * "active" means for the iterator: not expired for signing, and not
     28  * revoked.  The revocation half is covered by test_signkey_revocations.c.
     29  */
     30 #include "test_common.h"
     31 #include "exchange-database/insert_signkey.h"
     32 #include "exchange-database/get_signkey.h"
     33 #include "exchange-database/iterate_active_signkeys.h"
     34 
     35 
     36 /**
     37  * Build meta data for a signing key that is valid from an hour ago until
     38  * @a sign_offset from now.
     39  *
     40  * @param sign_offset how long the key remains valid for signing; may be
     41  *        negative to build an already expired key
     42  * @return the meta data
     43  */
     44 static struct TALER_EXCHANGEDB_SignkeyMetaData
     45 make_meta (struct GNUNET_TIME_Relative sign_offset)
     46 {
     47   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
     48   struct TALER_EXCHANGEDB_SignkeyMetaData meta;
     49 
     50   meta.start
     51     = GNUNET_TIME_absolute_to_timestamp (
     52         GNUNET_TIME_absolute_subtract (now,
     53                                        GNUNET_TIME_UNIT_HOURS));
     54   meta.expire_sign
     55     = GNUNET_TIME_absolute_to_timestamp (
     56         GNUNET_TIME_absolute_add (now,
     57                                   sign_offset));
     58   meta.expire_legal
     59     = GNUNET_TIME_absolute_to_timestamp (
     60         GNUNET_TIME_absolute_add (now,
     61                                   GNUNET_TIME_relative_multiply (
     62                                     GNUNET_TIME_UNIT_HOURS,
     63                                     24)));
     64   return meta;
     65 }
     66 
     67 
     68 /**
     69  * Nothing is known about a signing key that was never inserted.
     70  *
     71  * @param pg the database context
     72  * @return 0 on success
     73  */
     74 static int
     75 check_empty (struct TALER_EXCHANGEDB_PostgresContext *pg)
     76 {
     77   struct TALER_ExchangePublicKeyP exchange_pub;
     78   struct TALER_EXCHANGEDB_SignkeyMetaData meta;
     79 
     80   TDB_FILL (exchange_pub,
     81             1);
     82   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
     83           TALER_EXCHANGEDB_get_signkey (pg,
     84                                         &exchange_pub,
     85                                         &meta));
     86   FAILIF (0 != TDB_count (pg,
     87                           "FROM exchange_sign_keys"));
     88   return 0;
     89 }
     90 
     91 
     92 /**
     93  * Closure for #count_signkeys_cb().
     94  */
     95 struct CountContext
     96 {
     97   /**
     98    * Key we are looking for.
     99    */
    100   const struct TALER_ExchangePublicKeyP *exchange_pub;
    101 
    102   /**
    103    * How many keys did the callback see in total?
    104    */
    105   unsigned int total;
    106 
    107   /**
    108    * How many times did we see @e exchange_pub?
    109    */
    110   unsigned int matched;
    111 
    112   /**
    113    * Set if @e exchange_pub was reported with unexpected data.
    114    */
    115   bool mismatch;
    116 
    117   /**
    118    * Meta data reported for @e exchange_pub.
    119    */
    120   struct TALER_EXCHANGEDB_SignkeyMetaData meta;
    121 };
    122 
    123 
    124 /**
    125  * Callback for #TALER_EXCHANGEDB_iterate_active_signkeys().
    126  *
    127  * @param cls a `struct CountContext *`
    128  * @param exchange_pub public key of the exchange
    129  * @param meta meta data of @a exchange_pub
    130  * @param master_sig master signature over @a exchange_pub
    131  */
    132 static void
    133 count_signkeys_cb (void *cls,
    134                    const struct TALER_ExchangePublicKeyP *exchange_pub,
    135                    const struct TALER_EXCHANGEDB_SignkeyMetaData *meta,
    136                    const struct TALER_MasterSignatureP *master_sig)
    137 {
    138   struct CountContext *ctx = cls;
    139   struct TALER_MasterSignatureP expected;
    140 
    141   ctx->total++;
    142   if (0 != GNUNET_memcmp (exchange_pub,
    143                           ctx->exchange_pub))
    144     return;
    145   ctx->matched++;
    146   ctx->meta = *meta;
    147   TDB_FILL (expected,
    148             2);
    149   if (0 != GNUNET_memcmp (master_sig,
    150                           &expected))
    151     ctx->mismatch = true;
    152 }
    153 
    154 
    155 /**
    156  * Insert a signing key and read it back.
    157  *
    158  * @param pg the database context
    159  * @return 0 on success
    160  */
    161 static int
    162 check_insert_and_lookup (struct TALER_EXCHANGEDB_PostgresContext *pg)
    163 {
    164   struct TALER_ExchangePublicKeyP exchange_pub;
    165   struct TALER_MasterSignatureP master_sig;
    166   struct TALER_EXCHANGEDB_SignkeyMetaData meta;
    167   struct TALER_EXCHANGEDB_SignkeyMetaData got;
    168   struct CountContext ctx;
    169 
    170   TDB_FILL (exchange_pub,
    171             2);
    172   TDB_FILL (master_sig,
    173             2);
    174   meta = make_meta (GNUNET_TIME_UNIT_HOURS);
    175   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    176           TALER_EXCHANGEDB_insert_signkey (pg,
    177                                            &exchange_pub,
    178                                            &meta,
    179                                            &master_sig));
    180   memset (&got,
    181           0,
    182           sizeof (got));
    183   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    184           TALER_EXCHANGEDB_get_signkey (pg,
    185                                         &exchange_pub,
    186                                         &got));
    187   FAILIF (0 != GNUNET_memcmp (&got,
    188                               &meta));
    189 
    190   memset (&ctx,
    191           0,
    192           sizeof (ctx));
    193   ctx.exchange_pub = &exchange_pub;
    194   FAILIF (0 >=
    195           TALER_EXCHANGEDB_iterate_active_signkeys (pg,
    196                                                     &count_signkeys_cb,
    197                                                     &ctx));
    198   FAILIF (1 != ctx.matched);
    199   FAILIF (ctx.mismatch);
    200   FAILIF (0 != GNUNET_memcmp (&ctx.meta,
    201                               &meta));
    202   return 0;
    203 }
    204 
    205 
    206 /**
    207  * A key whose signing period is over is on file but not active.
    208  *
    209  * @param pg the database context
    210  * @return 0 on success
    211  */
    212 static int
    213 check_expired_is_inactive (struct TALER_EXCHANGEDB_PostgresContext *pg)
    214 {
    215   struct TALER_ExchangePublicKeyP exchange_pub;
    216   struct TALER_MasterSignatureP master_sig;
    217   struct TALER_EXCHANGEDB_SignkeyMetaData meta;
    218   struct TALER_EXCHANGEDB_SignkeyMetaData got;
    219   struct CountContext ctx;
    220 
    221   TDB_FILL (exchange_pub,
    222             3);
    223   TDB_FILL (master_sig,
    224             3);
    225   /* expired for signing half an hour ago */
    226   meta = make_meta (GNUNET_TIME_UNIT_ZERO);
    227   meta.expire_sign
    228     = GNUNET_TIME_absolute_to_timestamp (
    229         GNUNET_TIME_absolute_subtract (
    230           GNUNET_TIME_absolute_get (),
    231           GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES,
    232                                          30)));
    233   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    234           TALER_EXCHANGEDB_insert_signkey (pg,
    235                                            &exchange_pub,
    236                                            &meta,
    237                                            &master_sig));
    238   /* the row is there... */
    239   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
    240           TALER_EXCHANGEDB_get_signkey (pg,
    241                                         &exchange_pub,
    242                                         &got));
    243   /* ...but the iterator skips it */
    244   memset (&ctx,
    245           0,
    246           sizeof (ctx));
    247   ctx.exchange_pub = &exchange_pub;
    248   FAILIF (0 >=
    249           TALER_EXCHANGEDB_iterate_active_signkeys (pg,
    250                                                     &count_signkeys_cb,
    251                                                     &ctx));
    252   FAILIF (0 != ctx.matched);
    253   FAILIF (ctx.total !=
    254           TDB_count (pg,
    255                      "FROM exchange_sign_keys"
    256                      " WHERE expire_sign > %llu",
    257                      (unsigned long long)
    258                      GNUNET_TIME_absolute_get ().abs_value_us));
    259   FAILIF (2 != TDB_count (pg,
    260                           "FROM exchange_sign_keys"));
    261   return 0;
    262 }
    263 
    264 
    265 /**
    266  * The checks to run, in order.
    267  */
    268 static const struct TDB_Test tests[] = {
    269   { "exchange-sign-keys-empty",
    270     &check_empty },
    271   { "exchange-sign-keys-insert-and-lookup",
    272     &check_insert_and_lookup },
    273   { "exchange-sign-keys-expired-is-inactive",
    274     &check_expired_is_inactive },
    275   { NULL, NULL }
    276 };
    277 
    278 
    279 int
    280 main (int argc,
    281       char *const *argv)
    282 {
    283   return TDB_main (argc,
    284                    argv,
    285                    "test-exchange-sign-keys",
    286                    "Tests for the exchangedb `exchange_sign_keys' table",
    287                    tests);
    288 }
    289 
    290 
    291 /* end of test_exchange_sign_keys.c */