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 */