test_anastasis_db.c (12528B)
1 /* 2 This file is part of Anastasis 3 Copyright (C) 2020, 2021 Anastasis SARL 4 5 Anastasis is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Affero General Public License as published by the Free Software 7 Foundation; either version 3, or (at your option) any later version. 8 9 Anastasis 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 Affero General Public License for more details. 12 13 You should have received a copy of the GNU Affero General Public License along with 14 Anastasis; see the file COPYING.GPL. If not, see <http://www.gnu.org/licenses/> 15 */ 16 /** 17 * @file anastasis/test_anastasis_db.c 18 * @brief testcase for anastasis postgres db plugin 19 * @author Marcello Stanisci 20 * @author Christian Grothoff 21 */ 22 #include "platform.h" 23 #include "anastasis_database_lib.h" 24 #include "anastasis_util_lib.h" 25 #include <gnunet/gnunet_signatures.h> 26 27 28 #define FAILIF(cond) \ 29 do { \ 30 if (! (cond)) { break;} \ 31 GNUNET_break (0); \ 32 goto drop; \ 33 } while (0) 34 35 #define RND_BLK(ptr) \ 36 GNUNET_CRYPTO_random_block (ptr, sizeof (* \ 37 ptr)) 38 39 /** 40 * Global return value for the test. Initially -1, set to 0 upon 41 * completion. Other values indicate some kind of error. 42 */ 43 static int result; 44 45 /** 46 * Main function that will be run by the scheduler. 47 * 48 * @param cls closure with config 49 */ 50 static void 51 run (void *cls) 52 { 53 struct GNUNET_CONFIGURATION_Handle *cfg = cls; 54 struct TALER_Amount amount; 55 struct ANASTASIS_PaymentSecretP paymentSecretP; 56 struct ANASTASIS_CRYPTO_AccountPublicKeyP accountPubP; 57 struct ANASTASIS_AccountSignatureP accountSig; 58 struct ANASTASIS_AccountSignatureP res_account_sig; 59 struct GNUNET_HashCode recoveryDataHash; 60 struct GNUNET_HashCode res_recovery_data_hash; 61 struct GNUNET_HashCode r; 62 struct GNUNET_TIME_Relative rel_time; 63 struct ANASTASIS_CRYPTO_TruthUUIDP truth_uuid; 64 struct ANASTASIS_CRYPTO_EncryptedKeyShareP key_share; 65 unsigned int post_counter; 66 const char *mime_type; 67 const char *method; 68 uint32_t docVersion; 69 uint32_t res_version; 70 size_t recoverydatasize; 71 void *res_recovery_data = NULL; 72 struct ANASTASIS_CRYPTO_EncryptedKeyShareP res_key_share; 73 bool paid; 74 struct GNUNET_TIME_Timestamp pi_creation_date; 75 bool valid_counter; 76 uint32_t recversion = 1; 77 unsigned char aes_gcm_tag[16]; 78 const char *recovery_data = "RECOVERY_DATA"; 79 uint64_t challenge_code = 1234; 80 struct GNUNET_HashCode c_hash; 81 struct ANASTASIS_UploadSignaturePS usp = { 82 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TEST), 83 .purpose.size = htonl (sizeof (usp)) 84 }; 85 86 if (GNUNET_OK != 87 ANASTASIS_DB_init (cfg)) 88 { 89 result = 77; 90 return; 91 } 92 (void) ANASTASIS_DB_drop_tables (); 93 if (GNUNET_OK != 94 ANASTASIS_DB_create_tables ()) 95 { 96 result = 77; 97 return; 98 } 99 if (GNUNET_OK != 100 ANASTASIS_DB_preflight ()) 101 { 102 result = 77; 103 return; 104 } 105 106 GNUNET_CRYPTO_hash (recovery_data, 107 strlen (recovery_data), 108 &recoveryDataHash); 109 RND_BLK (&paymentSecretP); 110 RND_BLK (&aes_gcm_tag); 111 post_counter = 2; 112 mime_type = "Picture"; 113 method = "Method"; 114 TALER_string_to_amount ("EUR:30",&amount); 115 116 GNUNET_CRYPTO_random_block (&truth_uuid, 117 sizeof (truth_uuid)); 118 rel_time = GNUNET_TIME_UNIT_MONTHS; 119 120 GNUNET_assert (GNUNET_OK == 121 TALER_string_to_amount ("EUR:1", 122 &amount)); 123 124 memset (&key_share, 1, sizeof (key_share)); 125 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 126 ANASTASIS_DB_insert_truth ( 127 &truth_uuid, 128 &key_share, 129 mime_type, 130 "encrypted_truth", 131 strlen ("encrypted_truth"), 132 method, 133 rel_time)); 134 135 /* A TOTP time step may be consumed at most once, so that a code cannot be 136 replayed for as long as its window lasts. */ 137 { 138 struct ANASTASIS_CRYPTO_TruthUUIDP unknown_uuid; 139 140 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 141 ANASTASIS_DB_update_totp_counter (&truth_uuid, 142 1000)); 143 /* the same step again is the replay we are guarding against */ 144 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 145 ANASTASIS_DB_update_totp_counter (&truth_uuid, 146 1000)); 147 /* an earlier step, as a client with a slow clock would send */ 148 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 149 ANASTASIS_DB_update_totp_counter (&truth_uuid, 150 999)); 151 /* the next step is a fresh code and must still work */ 152 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 153 ANASTASIS_DB_update_totp_counter (&truth_uuid, 154 1001)); 155 memset (&unknown_uuid, 42, sizeof (unknown_uuid)); 156 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 157 ANASTASIS_DB_update_totp_counter (&unknown_uuid, 158 1)); 159 } 160 161 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 162 ANASTASIS_DB_get_recdoc_payment ( 163 &paymentSecretP, 164 &paid, 165 &valid_counter, 166 &pi_creation_date)); 167 168 memset (&accountPubP, 2, sizeof (accountPubP)); 169 memset (&accountSig, 3, sizeof (accountSig)); 170 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 171 ANASTASIS_DB_do_insert_recdoc_payment ( 172 &accountPubP, 173 post_counter, 174 &paymentSecretP, 175 &amount)); 176 { 177 struct GNUNET_TIME_Timestamp now = GNUNET_TIME_timestamp_get (); 178 struct GNUNET_TIME_Timestamp res_time; 179 struct GNUNET_TIME_Timestamp replay_time; 180 181 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 182 ANASTASIS_DB_do_update_account_lifetime ( 183 &accountPubP, 184 &paymentSecretP, 185 now, 186 rel_time, 187 &res_time)); 188 /* Lifetime is MAX(what the account had, now) + rel_time; the account 189 already carries the transient lifetime insert_recdoc_payment() gave 190 it, so all we can pin down is the lower bound. */ 191 FAILIF (GNUNET_TIME_timestamp_cmp ( 192 res_time, 193 <, 194 GNUNET_TIME_absolute_to_timestamp ( 195 GNUNET_TIME_absolute_add (now.abs_time, 196 rel_time)))); 197 /* Replaying the same payment must not extend the lifetime again. */ 198 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 199 ANASTASIS_DB_do_update_account_lifetime ( 200 &accountPubP, 201 &paymentSecretP, 202 now, 203 rel_time, 204 &replay_time)); 205 FAILIF (GNUNET_TIME_timestamp_cmp (replay_time, 206 !=, 207 res_time)); 208 } 209 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 210 ANASTASIS_DB_get_recdoc_payment ( 211 &paymentSecretP, 212 &paid, 213 &valid_counter, 214 &pi_creation_date)); 215 FAILIF (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != 216 ANASTASIS_DB_get_challenge_payment ( 217 &paymentSecretP, 218 &truth_uuid, 219 &paid)); 220 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 221 ANASTASIS_DB_insert_challenge_payment ( 222 &truth_uuid, 223 &paymentSecretP, 224 &amount)); 225 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 226 ANASTASIS_DB_update_to_challenge_payment_paid ( 227 &truth_uuid, 228 &paymentSecretP)); 229 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 230 ANASTASIS_DB_get_challenge_payment ( 231 &paymentSecretP, 232 &truth_uuid, 233 &paid)); 234 FAILIF (! paid); 235 FAILIF (ANASTASIS_DB_STORE_STATUS_SUCCESS != 236 ANASTASIS_DB_do_insert_recovery_document ( 237 &accountPubP, 238 &accountSig, 239 &recoveryDataHash, 240 recovery_data, 241 strlen (recovery_data), 242 "meta-data", 243 strlen ("meta-data"), 244 &paymentSecretP, 245 &docVersion)); 246 { 247 uint32_t vrs; 248 struct GNUNET_TIME_Timestamp exp; 249 250 FAILIF (ANASTASIS_DB_ACCOUNT_STATUS_VALID_HASH_RETURNED != 251 ANASTASIS_DB_get_account ( 252 &accountPubP, 253 &exp, 254 &r, 255 &vrs)); 256 } 257 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 258 ANASTASIS_DB_get_truth_key_share ( 259 &truth_uuid, 260 &res_key_share)); 261 FAILIF (0 != 262 GNUNET_memcmp (&res_key_share, 263 &key_share)); 264 265 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 266 ANASTASIS_DB_get_recovery_document ( 267 &accountPubP, 268 recversion, 269 &res_account_sig, 270 &res_recovery_data_hash, 271 &recoverydatasize, 272 &res_recovery_data)); 273 FAILIF (0 != memcmp (res_recovery_data, 274 recovery_data, 275 strlen (recovery_data))); 276 GNUNET_free (res_recovery_data); 277 278 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 279 ANASTASIS_DB_get_latest_recovery_document ( 280 &accountPubP, 281 &res_account_sig, 282 &res_recovery_data_hash, 283 &recoverydatasize, 284 &res_recovery_data, 285 &res_version)); 286 FAILIF (0 != memcmp (res_recovery_data, 287 recovery_data, 288 strlen (recovery_data))); 289 GNUNET_free (res_recovery_data); 290 291 { 292 struct GNUNET_TIME_Timestamp rt; 293 294 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 295 ANASTASIS_DB_insert_challenge_code ( 296 &truth_uuid, 297 GNUNET_TIME_UNIT_HOURS, 298 GNUNET_TIME_UNIT_DAYS, 299 3, /* retry counter */ 300 &rt, 301 &challenge_code)); 302 FAILIF (! GNUNET_TIME_absolute_is_zero (rt.abs_time)); 303 } 304 { 305 struct GNUNET_TIME_Timestamp rt; 306 uint64_t c2; 307 308 FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != 309 ANASTASIS_DB_insert_challenge_code ( 310 &truth_uuid, 311 GNUNET_TIME_UNIT_HOURS, 312 GNUNET_TIME_UNIT_DAYS, 313 3, /* retry counter */ 314 &rt, 315 &c2)); 316 FAILIF (c2 != challenge_code); 317 } 318 ANASTASIS_hash_answer (123, 319 &c_hash); 320 { 321 bool sat; 322 uint64_t r_code; 323 324 FAILIF (ANASTASIS_DB_CODE_STATUS_CHALLENGE_CODE_MISMATCH != 325 ANASTASIS_DB_do_verify_challenge_code ( 326 &truth_uuid, 327 &c_hash, 328 &r_code, 329 &sat)); 330 331 ANASTASIS_hash_answer (challenge_code, 332 &c_hash); 333 FAILIF (ANASTASIS_DB_CODE_STATUS_VALID_CODE_STORED != 334 ANASTASIS_DB_do_verify_challenge_code ( 335 &truth_uuid, 336 &c_hash, 337 &r_code, 338 &sat)); 339 } 340 if (-1 == result) 341 result = 0; 342 343 drop: 344 GNUNET_break (GNUNET_OK == 345 ANASTASIS_DB_drop_tables ()); 346 ANASTASIS_DB_fini (); 347 } 348 349 350 int 351 main (int argc, 352 char *const argv[]) 353 { 354 const char *plugin_name; 355 char *config_filename; 356 char *testname; 357 struct GNUNET_CONFIGURATION_Handle *cfg; 358 359 result = -1; 360 if (NULL == (plugin_name = strrchr (argv[0], (int) '-'))) 361 { 362 GNUNET_break (0); 363 return -1; 364 } 365 GNUNET_log_setup (argv[0], "DEBUG", NULL); 366 plugin_name++; 367 GNUNET_asprintf (&testname, 368 "%s", 369 plugin_name); 370 GNUNET_asprintf (&config_filename, 371 "test_anastasis_db_%s.conf", 372 testname); 373 cfg = GNUNET_CONFIGURATION_create (ANASTASIS_project_data ()); 374 if (GNUNET_OK != 375 GNUNET_CONFIGURATION_load (cfg, 376 config_filename)) 377 { 378 GNUNET_break (0); 379 GNUNET_free (config_filename); 380 GNUNET_free (testname); 381 return 2; 382 } 383 GNUNET_SCHEDULER_run (&run, 384 cfg); 385 GNUNET_CONFIGURATION_destroy (cfg); 386 GNUNET_free (config_filename); 387 GNUNET_free (testname); 388 return result; 389 } 390 391 392 /* end of test_anastasis_db.c */