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_signkey_revocations.c
18 : * @brief tests for the exchangedb functions whose primary table is
19 : * `signkey_revocations`
20 : * @author Christian Grothoff
21 : *
22 : * Covers #TALER_EXCHANGEDB_insert_signkey_revocation() and
23 : * #TALER_EXCHANGEDB_get_signkey_revocation().
24 : *
25 : * `signkey_revocations` references `exchange_sign_keys`, and both functions
26 : * find the row through the signing key rather than through the revocation's
27 : * own primary key -- so an unknown signing key has to come back as "no
28 : * revocation" rather than as an error. The fixture is inserted with
29 : * #TALER_EXCHANGEDB_insert_signkey(), whose own table is covered by
30 : * test_exchange_sign_keys.c.
31 : */
32 : #include "test_common.h"
33 : #include "exchange-database/insert_signkey.h"
34 : #include "exchange-database/insert_signkey_revocation.h"
35 : #include "exchange-database/get_signkey_revocation.h"
36 : #include "exchange-database/iterate_active_signkeys.h"
37 :
38 :
39 : /**
40 : * Insert a signing key that is valid for another hour.
41 : *
42 : * @param pg the database context
43 : * @param seed seed for the key and its master signature
44 : * @param[out] exchange_pub set to the public key
45 : */
46 : static void
47 2 : add_signkey (struct TALER_EXCHANGEDB_PostgresContext *pg,
48 : uint32_t seed,
49 : struct TALER_ExchangePublicKeyP *exchange_pub)
50 : {
51 2 : struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
52 : struct TALER_MasterSignatureP master_sig;
53 : struct TALER_EXCHANGEDB_SignkeyMetaData meta;
54 :
55 2 : TDB_fill (exchange_pub,
56 : sizeof (*exchange_pub),
57 : seed);
58 2 : TDB_FILL (master_sig,
59 : seed);
60 2 : meta.start = GNUNET_TIME_absolute_to_timestamp (now);
61 : meta.expire_sign
62 2 : = GNUNET_TIME_absolute_to_timestamp (
63 : GNUNET_TIME_absolute_add (now,
64 : GNUNET_TIME_UNIT_HOURS));
65 : meta.expire_legal
66 2 : = GNUNET_TIME_absolute_to_timestamp (
67 : GNUNET_TIME_absolute_add (now,
68 : GNUNET_TIME_relative_multiply (
69 : GNUNET_TIME_UNIT_HOURS,
70 : 24)));
71 2 : GNUNET_assert (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT ==
72 : TALER_EXCHANGEDB_insert_signkey (pg,
73 : exchange_pub,
74 : &meta,
75 : &master_sig));
76 2 : }
77 :
78 :
79 : /**
80 : * Counts the keys the active-signkey iterator reports.
81 : */
82 : struct CountContext
83 : {
84 : /**
85 : * Key we are looking for.
86 : */
87 : const struct TALER_ExchangePublicKeyP *exchange_pub;
88 :
89 : /**
90 : * How many times did we see @e exchange_pub?
91 : */
92 : unsigned int matched;
93 : };
94 :
95 :
96 : /**
97 : * Callback for #TALER_EXCHANGEDB_iterate_active_signkeys().
98 : *
99 : * @param cls a `struct CountContext *`
100 : * @param exchange_pub public key of the exchange
101 : * @param meta meta data of @a exchange_pub
102 : * @param master_sig master signature over @a exchange_pub
103 : */
104 : static void
105 3 : count_cb (void *cls,
106 : const struct TALER_ExchangePublicKeyP *exchange_pub,
107 : const struct TALER_EXCHANGEDB_SignkeyMetaData *meta,
108 : const struct TALER_MasterSignatureP *master_sig)
109 : {
110 3 : struct CountContext *ctx = cls;
111 :
112 : (void) meta;
113 : (void) master_sig;
114 3 : if (0 == GNUNET_memcmp (exchange_pub,
115 : ctx->exchange_pub))
116 1 : ctx->matched++;
117 3 : }
118 :
119 :
120 : /**
121 : * A signing key that does not exist has no revocation, and revoking it
122 : * does nothing.
123 : *
124 : * @param pg the database context
125 : * @return 0 on success
126 : */
127 : static int
128 1 : check_unknown_signkey (struct TALER_EXCHANGEDB_PostgresContext *pg)
129 : {
130 : struct TALER_ExchangePublicKeyP exchange_pub;
131 : struct TALER_MasterSignatureP master_sig;
132 : struct TALER_MasterSignatureP got;
133 :
134 1 : TDB_FILL (exchange_pub,
135 : 1);
136 1 : TDB_FILL (master_sig,
137 : 1);
138 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
139 : TALER_EXCHANGEDB_get_signkey_revocation (pg,
140 : &exchange_pub,
141 : &got));
142 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
143 : TALER_EXCHANGEDB_insert_signkey_revocation (pg,
144 : &exchange_pub,
145 : &master_sig));
146 1 : FAILIF (0 != TDB_count (pg,
147 : "FROM signkey_revocations"));
148 1 : return 0;
149 : }
150 :
151 :
152 : /**
153 : * A key that exists but was not revoked has no revocation either.
154 : *
155 : * @param pg the database context
156 : * @return 0 on success
157 : */
158 : static int
159 1 : check_not_revoked (struct TALER_EXCHANGEDB_PostgresContext *pg)
160 : {
161 : struct TALER_ExchangePublicKeyP exchange_pub;
162 : struct TALER_MasterSignatureP got;
163 :
164 1 : add_signkey (pg,
165 : 2,
166 : &exchange_pub);
167 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
168 : TALER_EXCHANGEDB_get_signkey_revocation (pg,
169 : &exchange_pub,
170 : &got));
171 1 : return 0;
172 : }
173 :
174 :
175 : /**
176 : * Revoking a key records the signature and takes the key out of the
177 : * active set.
178 : *
179 : * @param pg the database context
180 : * @return 0 on success
181 : */
182 : static int
183 1 : check_revoke (struct TALER_EXCHANGEDB_PostgresContext *pg)
184 : {
185 : struct TALER_ExchangePublicKeyP exchange_pub;
186 : struct TALER_MasterSignatureP master_sig;
187 : struct TALER_MasterSignatureP got;
188 : struct CountContext ctx;
189 :
190 1 : add_signkey (pg,
191 : 3,
192 : &exchange_pub);
193 1 : TDB_FILL (master_sig,
194 : 33);
195 :
196 : /* while unrevoked, the key is active */
197 1 : memset (&ctx,
198 : 0,
199 : sizeof (ctx));
200 1 : ctx.exchange_pub = &exchange_pub;
201 1 : FAILIF (0 >=
202 : TALER_EXCHANGEDB_iterate_active_signkeys (pg,
203 : &count_cb,
204 : &ctx));
205 1 : FAILIF (1 != ctx.matched);
206 :
207 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
208 : TALER_EXCHANGEDB_insert_signkey_revocation (pg,
209 : &exchange_pub,
210 : &master_sig));
211 1 : memset (&got,
212 : 0,
213 : sizeof (got));
214 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
215 : TALER_EXCHANGEDB_get_signkey_revocation (pg,
216 : &exchange_pub,
217 : &got));
218 1 : FAILIF (0 != GNUNET_memcmp (&got,
219 : &master_sig));
220 :
221 : /* ...and now it is gone from the active set */
222 1 : memset (&ctx,
223 : 0,
224 : sizeof (ctx));
225 1 : ctx.exchange_pub = &exchange_pub;
226 1 : FAILIF (0 >
227 : TALER_EXCHANGEDB_iterate_active_signkeys (pg,
228 : &count_cb,
229 : &ctx));
230 1 : FAILIF (0 != ctx.matched);
231 :
232 : /* the untouched key from the previous check is still fine */
233 : {
234 : struct TALER_ExchangePublicKeyP other;
235 :
236 1 : TDB_FILL (other,
237 : 2);
238 1 : FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS !=
239 : TALER_EXCHANGEDB_get_signkey_revocation (pg,
240 : &other,
241 : &got));
242 : }
243 1 : FAILIF (1 != TDB_count (pg,
244 : "FROM signkey_revocations"));
245 1 : return 0;
246 : }
247 :
248 :
249 : /**
250 : * The checks to run, in order.
251 : */
252 : static const struct TDB_Test tests[] = {
253 : { "signkey-revocations-unknown-signkey",
254 : &check_unknown_signkey },
255 : { "signkey-revocations-not-revoked",
256 : &check_not_revoked },
257 : { "signkey-revocations-revoke",
258 : &check_revoke },
259 : { NULL, NULL }
260 : };
261 :
262 :
263 : int
264 1 : main (int argc,
265 : char *const *argv)
266 : {
267 1 : return TDB_main (argc,
268 : argv,
269 : "test-signkey-revocations",
270 : "Tests for the exchangedb `signkey_revocations' table",
271 : tests);
272 : }
273 :
274 :
275 : /* end of test_signkey_revocations.c */
|