LCOV - code coverage report
Current view: top level - exchangedb - test_exchange_sign_keys.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 98.1 % 52 51
Test Date: 2026-09-11 18:55:36 Functions: 100.0 % 6 6

            Line data    Source code
       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            2 : make_meta (struct GNUNET_TIME_Relative sign_offset)
      46              : {
      47            2 :   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
      48              :   struct TALER_EXCHANGEDB_SignkeyMetaData meta;
      49              : 
      50              :   meta.start
      51            2 :     = GNUNET_TIME_absolute_to_timestamp (
      52              :         GNUNET_TIME_absolute_subtract (now,
      53              :                                        GNUNET_TIME_UNIT_HOURS));
      54              :   meta.expire_sign
      55            2 :     = GNUNET_TIME_absolute_to_timestamp (
      56              :         GNUNET_TIME_absolute_add (now,
      57              :                                   sign_offset));
      58              :   meta.expire_legal
      59            2 :     = GNUNET_TIME_absolute_to_timestamp (
      60              :         GNUNET_TIME_absolute_add (now,
      61              :                                   GNUNET_TIME_relative_multiply (
      62              :                                     GNUNET_TIME_UNIT_HOURS,
      63              :                                     24)));
      64            2 :   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            1 : check_empty (struct TALER_EXCHANGEDB_PostgresContext *pg)
      76              : {
      77              :   struct TALER_ExchangePublicKeyP exchange_pub;
      78              :   struct TALER_EXCHANGEDB_SignkeyMetaData meta;
      79              : 
      80            1 :   TDB_FILL (exchange_pub,
      81              :             1);
      82            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
      83              :           TALER_EXCHANGEDB_get_signkey (pg,
      84              :                                         &exchange_pub,
      85              :                                         &meta));
      86            1 :   FAILIF (0 != TDB_count (pg,
      87              :                           "FROM exchange_sign_keys"));
      88            1 :   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            2 : 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            2 :   struct CountContext *ctx = cls;
     139              :   struct TALER_MasterSignatureP expected;
     140              : 
     141            2 :   ctx->total++;
     142            2 :   if (0 != GNUNET_memcmp (exchange_pub,
     143              :                           ctx->exchange_pub))
     144            1 :     return;
     145            1 :   ctx->matched++;
     146            1 :   ctx->meta = *meta;
     147            1 :   TDB_FILL (expected,
     148              :             2);
     149            1 :   if (0 != GNUNET_memcmp (master_sig,
     150              :                           &expected))
     151            0 :     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            1 : 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            1 :   TDB_FILL (exchange_pub,
     171              :             2);
     172            1 :   TDB_FILL (master_sig,
     173              :             2);
     174            1 :   meta = make_meta (GNUNET_TIME_UNIT_HOURS);
     175            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     176              :           TALER_EXCHANGEDB_insert_signkey (pg,
     177              :                                            &exchange_pub,
     178              :                                            &meta,
     179              :                                            &master_sig));
     180            1 :   memset (&got,
     181              :           0,
     182              :           sizeof (got));
     183            1 :   FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
     184              :           TALER_EXCHANGEDB_get_signkey (pg,
     185              :                                         &exchange_pub,
     186              :                                         &got));
     187            1 :   FAILIF (0 != GNUNET_memcmp (&got,
     188              :                               &meta));
     189              : 
     190            1 :   memset (&ctx,
     191              :           0,
     192              :           sizeof (ctx));
     193            1 :   ctx.exchange_pub = &exchange_pub;
     194            1 :   FAILIF (0 >=
     195              :           TALER_EXCHANGEDB_iterate_active_signkeys (pg,
     196              :                                                     &count_signkeys_cb,
     197              :                                                     &ctx));
     198            1 :   FAILIF (1 != ctx.matched);
     199            1 :   FAILIF (ctx.mismatch);
     200            1 :   FAILIF (0 != GNUNET_memcmp (&ctx.meta,
     201              :                               &meta));
     202            1 :   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            1 : 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            1 :   TDB_FILL (exchange_pub,
     222              :             3);
     223            1 :   TDB_FILL (master_sig,
     224              :             3);
     225              :   /* expired for signing half an hour ago */
     226            1 :   meta = make_meta (GNUNET_TIME_UNIT_ZERO);
     227              :   meta.expire_sign
     228            1 :     = 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            1 :   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            1 :   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            1 :   memset (&ctx,
     245              :           0,
     246              :           sizeof (ctx));
     247            1 :   ctx.exchange_pub = &exchange_pub;
     248            1 :   FAILIF (0 >=
     249              :           TALER_EXCHANGEDB_iterate_active_signkeys (pg,
     250              :                                                     &count_signkeys_cb,
     251              :                                                     &ctx));
     252            1 :   FAILIF (0 != ctx.matched);
     253            1 :   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            1 :   FAILIF (2 != TDB_count (pg,
     260              :                           "FROM exchange_sign_keys"));
     261            1 :   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            1 : main (int argc,
     281              :       char *const *argv)
     282              : {
     283            1 :   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 */
        

Generated by: LCOV version 2.0-1