sync

Backup service to store encrypted wallet databases (experimental)
Log | Files | Refs | Submodules | README | LICENSE

test_sync_signatures.c (13493B)


      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 util/test_sync_signatures.c
     18  * @brief tests for the sync signatures and the object reference hash
     19  * @author Christian Grothoff
     20  */
     21 #include "platform.h"
     22 #include <gnunet/gnunet_util_lib.h>
     23 #include "sync/sync_service.h"
     24 #include "sync/sync_signatures.h"
     25 #include "sync/sync_util.h"
     26 
     27 
     28 #define FAILIF(cond)                            \
     29         do {                                          \
     30           if (! (cond)) break;                        \
     31           GNUNET_break (0);                           \
     32           return 1;                                   \
     33         } while (0)
     34 
     35 
     36 /**
     37  * Check #SYNC_object_refs_hash(): insensitive to the order the
     38  * references arrive in, sensitive to every UID and adjustment.
     39  *
     40  * @return 0 on success
     41  */
     42 static int
     43 test_refs_hash (void)
     44 {
     45   struct SYNC_ObjectUID uids[3];
     46   struct SYNC_ObjectUID shuffled[3];
     47   const int16_t incs[3] = { 1, -2, 3 };
     48   int16_t shuffled_incs[3];
     49   struct GNUNET_HashCode h;
     50   struct GNUNET_HashCode h2;
     51 
     52   for (unsigned int i = 0; i < 3; i++)
     53     GNUNET_CRYPTO_random_block (&uids[i],
     54                                 sizeof (uids[i]));
     55 
     56   /* An empty reference set hashes deterministically */
     57   FAILIF (GNUNET_OK !=
     58           SYNC_object_refs_hash (0,
     59                                  NULL,
     60                                  NULL,
     61                                  &h));
     62   FAILIF (GNUNET_OK !=
     63           SYNC_object_refs_hash (0,
     64                                  uids,
     65                                  incs,
     66                                  &h2));
     67   FAILIF (0 != GNUNET_memcmp (&h,
     68                               &h2));
     69 
     70   /* ... and differs from any non-empty set */
     71   FAILIF (GNUNET_OK !=
     72           SYNC_object_refs_hash (3,
     73                                  uids,
     74                                  incs,
     75                                  &h));
     76   FAILIF (0 == GNUNET_memcmp (&h,
     77                               &h2));
     78 
     79   /* JSON object member order is not preserved, so reordering the
     80      references must not change the hash */
     81   shuffled[0] = uids[2];
     82   shuffled[1] = uids[0];
     83   shuffled[2] = uids[1];
     84   shuffled_incs[0] = incs[2];
     85   shuffled_incs[1] = incs[0];
     86   shuffled_incs[2] = incs[1];
     87   FAILIF (GNUNET_OK !=
     88           SYNC_object_refs_hash (3,
     89                                  shuffled,
     90                                  shuffled_incs,
     91                                  &h2));
     92   FAILIF (0 != GNUNET_memcmp (&h,
     93                               &h2));
     94 
     95   /* Changing an adjustment changes the hash */
     96   shuffled_incs[0] = (int16_t) (shuffled_incs[0] + 1);
     97   FAILIF (GNUNET_OK !=
     98           SYNC_object_refs_hash (3,
     99                                  shuffled,
    100                                  shuffled_incs,
    101                                  &h2));
    102   FAILIF (0 == GNUNET_memcmp (&h,
    103                               &h2));
    104 
    105   /* Changing a UID changes the hash */
    106   shuffled_incs[0] = incs[2];
    107   GNUNET_CRYPTO_random_block (&shuffled[0],
    108                               sizeof (shuffled[0]));
    109   FAILIF (GNUNET_OK !=
    110           SYNC_object_refs_hash (3,
    111                                  shuffled,
    112                                  shuffled_incs,
    113                                  &h2));
    114   FAILIF (0 == GNUNET_memcmp (&h,
    115                               &h2));
    116 
    117   /* Dropping a reference changes the hash */
    118   FAILIF (GNUNET_OK !=
    119           SYNC_object_refs_hash (2,
    120                                  uids,
    121                                  incs,
    122                                  &h2));
    123   FAILIF (0 == GNUNET_memcmp (&h,
    124                               &h2));
    125 
    126   /* A repeated UID cannot be carried on the wire */
    127   shuffled[0] = uids[0];
    128   shuffled[1] = uids[0];
    129   shuffled[2] = uids[1];
    130   FAILIF (GNUNET_SYSERR !=
    131           SYNC_object_refs_hash (3,
    132                                  shuffled,
    133                                  shuffled_incs,
    134                                  &h2));
    135   return 0;
    136 }
    137 
    138 
    139 /**
    140  * Check that references survive the wire encoding with their hash
    141  * intact; this is what makes the signature verify server-side.
    142  *
    143  * @return 0 on success
    144  */
    145 static int
    146 test_refs_json_roundtrip (void)
    147 {
    148   struct SYNC_ObjectUID uids[3];
    149   const int16_t incs[3] = { 5, -1, 32767 };
    150   struct GNUNET_HashCode h;
    151   struct GNUNET_HashCode h2;
    152   json_t *refs;
    153   size_t parsed_len;
    154   struct SYNC_ObjectUID *parsed_uids;
    155   int16_t *parsed_incs;
    156 
    157   for (unsigned int i = 0; i < 3; i++)
    158     GNUNET_CRYPTO_random_block (&uids[i],
    159                                 sizeof (uids[i]));
    160   FAILIF (GNUNET_OK !=
    161           SYNC_object_refs_hash (3,
    162                                  uids,
    163                                  incs,
    164                                  &h));
    165   refs = SYNC_object_refs_serialize (3,
    166                                      uids,
    167                                      incs);
    168   FAILIF (NULL == refs);
    169   FAILIF (GNUNET_OK !=
    170           SYNC_object_refs_parse (refs,
    171                                   &parsed_len,
    172                                   &parsed_uids,
    173                                   &parsed_incs));
    174   json_decref (refs);
    175   FAILIF (3 != parsed_len);
    176   FAILIF (GNUNET_OK !=
    177           SYNC_object_refs_hash (parsed_len,
    178                                  parsed_uids,
    179                                  parsed_incs,
    180                                  &h2));
    181   GNUNET_free (parsed_uids);
    182   GNUNET_free (parsed_incs);
    183   FAILIF (0 != GNUNET_memcmp (&h,
    184                               &h2));
    185   return 0;
    186 }
    187 
    188 
    189 /**
    190  * Check that the block upload signature covers the object references.
    191  *
    192  * @return 0 on success
    193  */
    194 static int
    195 test_upload_sig (void)
    196 {
    197   struct SYNC_AccountPrivateKeyP priv;
    198   struct SYNC_AccountPublicKeyP pub;
    199   struct SYNC_AccountSignatureP sig;
    200   struct SYNC_BlockNonce nonce;
    201   struct SYNC_BlockNonce prev;
    202   struct GNUNET_HashCode old_hash;
    203   struct GNUNET_HashCode new_hash;
    204   struct SYNC_ObjectUID uid;
    205   int16_t inc = 1;
    206   int16_t tampered_inc = 2;
    207   struct GNUNET_HashCode refs_hash;
    208   struct GNUNET_HashCode other_refs_hash;
    209 
    210   GNUNET_CRYPTO_eddsa_key_create (&priv.eddsa_priv);
    211   GNUNET_CRYPTO_eddsa_key_get_public (&priv.eddsa_priv,
    212                                       &pub.eddsa_pub);
    213   GNUNET_CRYPTO_random_block (&nonce,
    214                               sizeof (nonce));
    215   GNUNET_CRYPTO_random_block (&prev,
    216                               sizeof (prev));
    217   GNUNET_CRYPTO_random_block (&uid,
    218                               sizeof (uid));
    219   GNUNET_CRYPTO_hash ("old", 3, &old_hash);
    220   GNUNET_CRYPTO_hash ("new", 3, &new_hash);
    221   FAILIF (GNUNET_OK !=
    222           SYNC_object_refs_hash (1,
    223                                  &uid,
    224                                  &inc,
    225                                  &refs_hash));
    226   FAILIF (GNUNET_OK !=
    227           SYNC_object_refs_hash (1,
    228                                  &uid,
    229                                  &tampered_inc,
    230                                  &other_refs_hash));
    231   SYNC_block_upload_sign (&priv,
    232                           &nonce,
    233                           &prev,
    234                           NULL,
    235                           &old_hash,
    236                           &new_hash,
    237                           &refs_hash,
    238                           &sig);
    239   FAILIF (GNUNET_OK !=
    240           SYNC_block_upload_verify (&pub,
    241                                     &nonce,
    242                                     &prev,
    243                                     NULL,
    244                                     &old_hash,
    245                                     &new_hash,
    246                                     &refs_hash,
    247                                     &sig));
    248   /* Altering the adjustment invalidates the signature */
    249   FAILIF (GNUNET_OK ==
    250           SYNC_block_upload_verify (&pub,
    251                                     &nonce,
    252                                     &prev,
    253                                     NULL,
    254                                     &old_hash,
    255                                     &new_hash,
    256                                     &other_refs_hash,
    257                                     &sig));
    258   /* So does stripping the references altogether */
    259   FAILIF (GNUNET_OK !=
    260           SYNC_object_refs_hash (0,
    261                                  NULL,
    262                                  NULL,
    263                                  &other_refs_hash));
    264   FAILIF (GNUNET_OK ==
    265           SYNC_block_upload_verify (&pub,
    266                                     &nonce,
    267                                     &prev,
    268                                     NULL,
    269                                     &old_hash,
    270                                     &new_hash,
    271                                     &other_refs_hash,
    272                                     &sig));
    273   /* The rest of the signed data is still covered */
    274   FAILIF (GNUNET_OK ==
    275           SYNC_block_upload_verify (&pub,
    276                                     &nonce,
    277                                     NULL,
    278                                     NULL,
    279                                     &old_hash,
    280                                     &new_hash,
    281                                     &refs_hash,
    282                                     &sig));
    283   return 0;
    284 }
    285 
    286 
    287 /**
    288  * Check that the block delete signature covers the object references.
    289  *
    290  * @return 0 on success
    291  */
    292 static int
    293 test_delete_sig (void)
    294 {
    295   struct SYNC_AccountPrivateKeyP priv;
    296   struct SYNC_AccountPublicKeyP pub;
    297   struct SYNC_AccountSignatureP sig;
    298   struct SYNC_BlockNonce nonce;
    299   struct GNUNET_HashCode block_hash;
    300   struct SYNC_ObjectUID uid;
    301   int16_t dec = -1;
    302   struct GNUNET_HashCode refs_hash;
    303   struct GNUNET_HashCode empty_refs_hash;
    304 
    305   GNUNET_CRYPTO_eddsa_key_create (&priv.eddsa_priv);
    306   GNUNET_CRYPTO_eddsa_key_get_public (&priv.eddsa_priv,
    307                                       &pub.eddsa_pub);
    308   GNUNET_CRYPTO_random_block (&nonce,
    309                               sizeof (nonce));
    310   GNUNET_CRYPTO_random_block (&uid,
    311                               sizeof (uid));
    312   GNUNET_CRYPTO_hash ("block", 5, &block_hash);
    313   FAILIF (GNUNET_OK !=
    314           SYNC_object_refs_hash (1,
    315                                  &uid,
    316                                  &dec,
    317                                  &refs_hash));
    318   FAILIF (GNUNET_OK !=
    319           SYNC_object_refs_hash (0,
    320                                  NULL,
    321                                  NULL,
    322                                  &empty_refs_hash));
    323   SYNC_block_delete_sign (&priv,
    324                           &nonce,
    325                           NULL,
    326                           NULL,
    327                           &block_hash,
    328                           &refs_hash,
    329                           &sig);
    330   FAILIF (GNUNET_OK !=
    331           SYNC_block_delete_verify (&pub,
    332                                     &nonce,
    333                                     NULL,
    334                                     NULL,
    335                                     &block_hash,
    336                                     &refs_hash,
    337                                     &sig));
    338   FAILIF (GNUNET_OK ==
    339           SYNC_block_delete_verify (&pub,
    340                                     &nonce,
    341                                     NULL,
    342                                     NULL,
    343                                     &block_hash,
    344                                     &empty_refs_hash,
    345                                     &sig));
    346   return 0;
    347 }
    348 
    349 
    350 /**
    351  * Check the object upload signature round trip.
    352  *
    353  * @return 0 on success
    354  */
    355 static int
    356 test_object_sig (void)
    357 {
    358   struct SYNC_AccountPrivateKeyP priv;
    359   struct SYNC_AccountPublicKeyP pub;
    360   struct SYNC_AccountSignatureP sig;
    361   struct SYNC_ObjectUID uid;
    362   struct SYNC_ObjectUID other_uid;
    363   struct GNUNET_HashCode hash;
    364 
    365   GNUNET_CRYPTO_eddsa_key_create (&priv.eddsa_priv);
    366   GNUNET_CRYPTO_eddsa_key_get_public (&priv.eddsa_priv,
    367                                       &pub.eddsa_pub);
    368   GNUNET_CRYPTO_random_block (&uid,
    369                               sizeof (uid));
    370   GNUNET_CRYPTO_random_block (&other_uid,
    371                               sizeof (other_uid));
    372   GNUNET_CRYPTO_hash ("object", 6, &hash);
    373   SYNC_object_upload_sign (&priv,
    374                            &uid,
    375                            &hash,
    376                            &sig);
    377   FAILIF (GNUNET_OK !=
    378           SYNC_object_upload_verify (&pub,
    379                                      &uid,
    380                                      &hash,
    381                                      &sig));
    382   FAILIF (GNUNET_OK ==
    383           SYNC_object_upload_verify (&pub,
    384                                      &other_uid,
    385                                      &hash,
    386                                      &sig));
    387   return 0;
    388 }
    389 
    390 
    391 int
    392 main (int argc,
    393       char *const argv[])
    394 {
    395   (void) argc;
    396   GNUNET_log_setup (argv[0],
    397                     "WARNING",
    398                     NULL);
    399   if (0 != test_refs_hash ())
    400     return 1;
    401   if (0 != test_refs_json_roundtrip ())
    402     return 1;
    403   if (0 != test_upload_sig ())
    404     return 1;
    405   if (0 != test_delete_sig ())
    406     return 1;
    407   if (0 != test_object_sig ())
    408     return 1;
    409   return 0;
    410 }
    411 
    412 
    413 /* end of test_sync_signatures.c */