Line data Source code
1 : /*
2 : This file is part of TALER
3 : (C) 2015, 2020-2024 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 : /**
18 : * @file util/test_crypto.c
19 : * @brief Tests for Taler-specific crypto logic
20 : * @author Christian Grothoff <christian@grothoff.org>
21 : */
22 : #include "taler/platform.h"
23 : #include "taler/taler_util.h"
24 :
25 :
26 : /**
27 : * Test high-level link encryption/decryption API.
28 : *
29 : * @return 0 on success
30 : */
31 : static int
32 1 : test_high_level (void)
33 : {
34 : struct TALER_CoinSpendPrivateKeyP coin_priv;
35 : struct TALER_CoinSpendPublicKeyP coin_pub;
36 : struct TALER_TransferPrivateKeyP trans_priv;
37 : struct TALER_TransferPublicKeyP trans_pub;
38 : struct TALER_TransferSecretP secret;
39 : struct TALER_TransferSecretP secret2;
40 : union GNUNET_CRYPTO_BlindingSecretP bks1;
41 : union GNUNET_CRYPTO_BlindingSecretP bks2;
42 : struct TALER_CoinSpendPrivateKeyP coin_priv1;
43 : struct TALER_CoinSpendPrivateKeyP coin_priv2;
44 : struct TALER_PlanchetMasterSecretP ps1;
45 : struct TALER_PlanchetMasterSecretP ps2;
46 1 : struct GNUNET_CRYPTO_BlindingInputValues bi = {
47 : .cipher = GNUNET_CRYPTO_BSA_RSA
48 : };
49 1 : struct TALER_ExchangeBlindingValues alg1 = {
50 : .blinding_inputs = &bi
51 : };
52 1 : struct TALER_ExchangeBlindingValues alg2 = {
53 : .blinding_inputs = &bi
54 : };
55 :
56 1 : GNUNET_CRYPTO_eddsa_key_create (&coin_priv.eddsa_priv);
57 1 : GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv.eddsa_priv,
58 : &coin_pub.eddsa_pub);
59 1 : GNUNET_CRYPTO_ecdhe_key_create (&trans_priv.ecdhe_priv);
60 1 : GNUNET_CRYPTO_ecdhe_key_get_public (&trans_priv.ecdhe_priv,
61 : &trans_pub.ecdhe_pub);
62 1 : TALER_link_derive_transfer_secret (&coin_priv,
63 : &trans_priv,
64 : &secret);
65 1 : TALER_link_reveal_transfer_secret (&trans_priv,
66 : &coin_pub,
67 : &secret2);
68 1 : GNUNET_assert (0 ==
69 : GNUNET_memcmp (&secret,
70 : &secret2));
71 1 : TALER_link_recover_transfer_secret (&trans_pub,
72 : &coin_priv,
73 : &secret2);
74 1 : GNUNET_assert (0 ==
75 : GNUNET_memcmp (&secret,
76 : &secret2));
77 1 : TALER_transfer_secret_to_planchet_secret (&secret,
78 : 0,
79 : &ps1);
80 1 : TALER_planchet_setup_coin_priv (&ps1,
81 : &alg1,
82 : &coin_priv1);
83 1 : TALER_planchet_blinding_secret_create (&ps1,
84 : &alg1,
85 : &bks1);
86 1 : TALER_transfer_secret_to_planchet_secret (&secret,
87 : 1,
88 : &ps2);
89 1 : TALER_planchet_setup_coin_priv (&ps2,
90 : &alg2,
91 : &coin_priv2);
92 1 : TALER_planchet_blinding_secret_create (&ps2,
93 : &alg2,
94 : &bks2);
95 1 : GNUNET_assert (0 !=
96 : GNUNET_memcmp (&ps1,
97 : &ps2));
98 1 : GNUNET_assert (0 !=
99 : GNUNET_memcmp (&coin_priv1,
100 : &coin_priv2));
101 1 : GNUNET_assert (0 !=
102 : GNUNET_memcmp (&bks1,
103 : &bks2));
104 1 : return 0;
105 : }
106 :
107 :
108 : static struct TALER_AgeMask age_mask = {
109 : .bits = 1 | 1 << 8 | 1 << 10 | 1 << 12
110 : | 1 << 14 | 1 << 16 | 1 << 18 | 1 << 21
111 : };
112 :
113 : /**
114 : * Test the basic planchet functionality of creating a fresh planchet
115 : * and extracting the respective signature.
116 : *
117 : * @return 0 on success
118 : */
119 : static int
120 2 : test_planchets_rsa (uint8_t age)
121 : {
122 : struct TALER_PlanchetMasterSecretP ps;
123 : struct TALER_CoinSpendPrivateKeyP coin_priv;
124 : union GNUNET_CRYPTO_BlindingSecretP bks;
125 : struct TALER_DenominationPrivateKey dk_priv;
126 : struct TALER_DenominationPublicKey dk_pub;
127 : const struct TALER_ExchangeBlindingValues *alg_values;
128 : struct TALER_PlanchetDetail pd;
129 : struct TALER_BlindedDenominationSignature blind_sig;
130 : struct TALER_FreshCoin coin;
131 : struct TALER_CoinPubHashP c_hash;
132 2 : struct TALER_AgeCommitmentHashP *ach = NULL;
133 2 : struct TALER_AgeCommitmentHashP ah = {0};
134 :
135 2 : alg_values = TALER_denom_ewv_rsa_singleton ();
136 2 : if (0 < age)
137 : {
138 : struct TALER_AgeCommitmentProof acp;
139 : struct GNUNET_HashCode seed;
140 :
141 1 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
142 : &seed,
143 : sizeof(seed));
144 1 : TALER_age_restriction_commit (&age_mask,
145 : age,
146 : &seed,
147 : &acp);
148 1 : TALER_age_commitment_hash (&acp.commitment,
149 : &ah);
150 1 : ach = &ah;
151 1 : TALER_age_commitment_proof_free (&acp);
152 : }
153 :
154 2 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
155 : &ps,
156 : sizeof (ps));
157 2 : GNUNET_log_skip (1, GNUNET_YES);
158 2 : GNUNET_assert (GNUNET_SYSERR ==
159 : TALER_denom_priv_create (&dk_priv,
160 : &dk_pub,
161 : GNUNET_CRYPTO_BSA_INVALID));
162 2 : GNUNET_log_skip (1, GNUNET_YES);
163 2 : GNUNET_assert (GNUNET_SYSERR ==
164 : TALER_denom_priv_create (&dk_priv,
165 : &dk_pub,
166 : 42));
167 :
168 2 : GNUNET_assert (GNUNET_OK ==
169 : TALER_denom_priv_create (&dk_priv,
170 : &dk_pub,
171 : GNUNET_CRYPTO_BSA_RSA,
172 : 1024));
173 2 : TALER_planchet_setup_coin_priv (&ps,
174 : alg_values,
175 : &coin_priv);
176 2 : TALER_planchet_blinding_secret_create (&ps,
177 : alg_values,
178 : &bks);
179 2 : GNUNET_assert (GNUNET_OK ==
180 : TALER_planchet_prepare (&dk_pub,
181 : alg_values,
182 : &bks,
183 : NULL,
184 : &coin_priv,
185 : ach,
186 : &c_hash,
187 : &pd));
188 2 : GNUNET_assert (GNUNET_OK ==
189 : TALER_denom_sign_blinded (&blind_sig,
190 : &dk_priv,
191 : false,
192 : &pd.blinded_planchet));
193 2 : TALER_planchet_detail_free (&pd);
194 2 : GNUNET_assert (GNUNET_OK ==
195 : TALER_planchet_to_coin (&dk_pub,
196 : &blind_sig,
197 : &bks,
198 : &coin_priv,
199 : ach,
200 : &c_hash,
201 : alg_values,
202 : &coin));
203 2 : TALER_blinded_denom_sig_free (&blind_sig);
204 2 : TALER_denom_sig_free (&coin.sig);
205 2 : TALER_denom_priv_free (&dk_priv);
206 2 : TALER_denom_pub_free (&dk_pub);
207 2 : return 0;
208 : }
209 :
210 :
211 : /**
212 : * Test the basic planchet functionality of creating a fresh planchet with CS denomination
213 : * and extracting the respective signature.
214 : *
215 : * @return 0 on success
216 : */
217 : static int
218 2 : test_planchets_cs (uint8_t age)
219 : {
220 : struct TALER_PlanchetMasterSecretP ps;
221 : struct TALER_CoinSpendPrivateKeyP coin_priv;
222 : union GNUNET_CRYPTO_BlindingSecretP bks;
223 : struct TALER_DenominationPrivateKey dk_priv;
224 : struct TALER_DenominationPublicKey dk_pub;
225 : struct TALER_PlanchetDetail pd;
226 : struct TALER_CoinPubHashP c_hash;
227 : union GNUNET_CRYPTO_BlindSessionNonce nonce;
228 : struct TALER_BlindedDenominationSignature blind_sig;
229 : struct TALER_FreshCoin coin;
230 : struct TALER_ExchangeBlindingValues alg_values;
231 2 : struct TALER_AgeCommitmentHashP *ach = NULL;
232 2 : struct TALER_AgeCommitmentHashP ah = {0};
233 :
234 2 : if (0 < age)
235 : {
236 : struct TALER_AgeCommitmentProof acp;
237 : struct GNUNET_HashCode seed;
238 :
239 1 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
240 : &seed,
241 : sizeof(seed));
242 1 : TALER_age_restriction_commit (&age_mask,
243 : age,
244 : &seed,
245 : &acp);
246 1 : TALER_age_commitment_hash (&acp.commitment,
247 : &ah);
248 1 : ach = &ah;
249 1 : TALER_age_commitment_proof_free (&acp);
250 : }
251 :
252 2 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
253 : &ps,
254 : sizeof (ps));
255 2 : GNUNET_assert (GNUNET_OK ==
256 : TALER_denom_priv_create (&dk_priv,
257 : &dk_pub,
258 : GNUNET_CRYPTO_BSA_CS));
259 : #pragma message "phase out TALER_cs_withdraw_nonce_derive"
260 2 : TALER_cs_withdraw_nonce_derive (
261 : &ps,
262 : &nonce.cs_nonce);
263 : // FIXME: define Taler abstraction for this:
264 : alg_values.blinding_inputs
265 2 : = GNUNET_CRYPTO_get_blinding_input_values (dk_priv.bsign_priv_key,
266 : &nonce,
267 : "rw");
268 2 : TALER_denom_pub_hash (&dk_pub,
269 : &pd.denom_pub_hash);
270 2 : TALER_planchet_setup_coin_priv (&ps,
271 : &alg_values,
272 : &coin_priv);
273 2 : TALER_planchet_blinding_secret_create (&ps,
274 : &alg_values,
275 : &bks);
276 2 : GNUNET_assert (GNUNET_OK ==
277 : TALER_planchet_prepare (&dk_pub,
278 : &alg_values,
279 : &bks,
280 : &nonce,
281 : &coin_priv,
282 : ach,
283 : &c_hash,
284 : &pd));
285 2 : GNUNET_assert (GNUNET_OK ==
286 : TALER_denom_sign_blinded (&blind_sig,
287 : &dk_priv,
288 : false,
289 : &pd.blinded_planchet));
290 2 : GNUNET_assert (GNUNET_OK ==
291 : TALER_planchet_to_coin (&dk_pub,
292 : &blind_sig,
293 : &bks,
294 : &coin_priv,
295 : ach,
296 : &c_hash,
297 : &alg_values,
298 : &coin));
299 2 : TALER_blinded_denom_sig_free (&blind_sig);
300 2 : TALER_denom_sig_free (&coin.sig);
301 2 : TALER_denom_priv_free (&dk_priv);
302 2 : TALER_denom_pub_free (&dk_pub);
303 2 : return 0;
304 : }
305 :
306 :
307 : /**
308 : * Test the basic planchet functionality of creating a fresh planchet
309 : * and extracting the respective signature.
310 : * Calls test_planchets_rsa and test_planchets_cs
311 : *
312 : * @return 0 on success
313 : */
314 : static int
315 2 : test_planchets (uint8_t age)
316 : {
317 2 : if (0 != test_planchets_rsa (age))
318 0 : return -1;
319 2 : return test_planchets_cs (age);
320 : }
321 :
322 :
323 : static int
324 1 : test_exchange_sigs (void)
325 : {
326 1 : const struct TALER_FullPayto pt = {
327 : .full_payto
328 : = (char *) "payto://x-taler-bank/localhost/Account?receiver-name=ACC"
329 : };
330 1 : const struct TALER_FullPayto pto = {
331 : .full_payto
332 : = (char *) "payto://x-taler-bank/localhost/Other?receiver-name=OTH"
333 : };
334 : struct TALER_MasterPrivateKeyP priv;
335 : struct TALER_MasterPublicKeyP pub;
336 : struct TALER_MasterSignatureP sig;
337 : json_t *rest;
338 :
339 1 : GNUNET_CRYPTO_eddsa_key_create (&priv.eddsa_priv);
340 1 : rest = json_array ();
341 1 : GNUNET_assert (NULL != rest);
342 1 : TALER_exchange_wire_signature_make (pt,
343 : NULL,
344 : "https://example.com/",
345 : NULL,
346 : rest,
347 : rest,
348 : &priv,
349 : &sig);
350 1 : GNUNET_CRYPTO_eddsa_key_get_public (&priv.eddsa_priv,
351 : &pub.eddsa_pub);
352 1 : if (GNUNET_OK !=
353 1 : TALER_exchange_wire_signature_check (pt,
354 : NULL,
355 : "https://example.com/",
356 : NULL,
357 : rest,
358 : rest,
359 : &pub,
360 : &sig))
361 : {
362 0 : GNUNET_break (0);
363 0 : return 1;
364 : }
365 1 : if (GNUNET_OK ==
366 1 : TALER_exchange_wire_signature_check (
367 : pto,
368 : NULL,
369 : "https://example.com/",
370 : NULL,
371 : rest,
372 : rest,
373 : &pub,
374 : &sig))
375 : {
376 0 : GNUNET_break (0);
377 0 : return 1;
378 : }
379 1 : if (GNUNET_OK ==
380 1 : TALER_exchange_wire_signature_check (
381 : pt,
382 : "http://example.com/",
383 : NULL,
384 : NULL,
385 : rest,
386 : rest,
387 : &pub,
388 : &sig))
389 : {
390 0 : GNUNET_break (0);
391 0 : return 1;
392 : }
393 1 : json_decref (rest);
394 1 : return 0;
395 : }
396 :
397 :
398 : static int
399 1 : test_merchant_sigs (void)
400 : {
401 1 : const struct TALER_FullPayto pt = {
402 : .full_payto
403 : = (char *) "payto://x-taler-bank/localhost/Account?receiver-name=ACC"
404 : };
405 1 : const struct TALER_FullPayto pto = {
406 : .full_payto
407 : = (char *) "payto://x-taler-bank/localhost/Other?receiver-name=OTH"
408 : };
409 : struct TALER_WireSaltP salt;
410 : struct TALER_MerchantPrivateKeyP priv;
411 : struct TALER_MerchantPublicKeyP pub;
412 : struct TALER_MerchantSignatureP sig;
413 :
414 1 : GNUNET_CRYPTO_eddsa_key_create (&priv.eddsa_priv);
415 1 : memset (&salt,
416 : 42,
417 : sizeof (salt));
418 1 : TALER_merchant_wire_signature_make (pt,
419 : &salt,
420 : &priv,
421 : &sig);
422 1 : GNUNET_CRYPTO_eddsa_key_get_public (&priv.eddsa_priv,
423 : &pub.eddsa_pub);
424 1 : if (GNUNET_OK !=
425 1 : TALER_merchant_wire_signature_check (pt,
426 : &salt,
427 : &pub,
428 : &sig))
429 : {
430 0 : GNUNET_break (0);
431 0 : return 1;
432 : }
433 1 : if (GNUNET_OK ==
434 1 : TALER_merchant_wire_signature_check (
435 : pto,
436 : &salt,
437 : &pub,
438 : &sig))
439 : {
440 0 : GNUNET_break (0);
441 0 : return 1;
442 : }
443 1 : memset (&salt,
444 : 43,
445 : sizeof (salt));
446 1 : if (GNUNET_OK ==
447 1 : TALER_merchant_wire_signature_check (pt,
448 : &salt,
449 : &pub,
450 : &sig))
451 : {
452 0 : GNUNET_break (0);
453 0 : return 1;
454 : }
455 1 : return 0;
456 : }
457 :
458 :
459 : static int
460 1 : test_contracts (void)
461 : {
462 : struct TALER_ContractDiffiePrivateP cpriv;
463 : struct TALER_PurseContractPublicKeyP purse_pub;
464 : struct TALER_PurseContractPrivateKeyP purse_priv;
465 : void *econtract;
466 : size_t econtract_size;
467 : struct TALER_PurseMergePrivateKeyP mpriv_in;
468 : struct TALER_PurseMergePrivateKeyP mpriv_out;
469 : json_t *c;
470 :
471 1 : GNUNET_CRYPTO_ecdhe_key_create (&cpriv.ecdhe_priv);
472 1 : GNUNET_CRYPTO_eddsa_key_create (&purse_priv.eddsa_priv);
473 1 : GNUNET_CRYPTO_eddsa_key_get_public (&purse_priv.eddsa_priv,
474 : &purse_pub.eddsa_pub);
475 1 : memset (&mpriv_in,
476 : 42,
477 : sizeof (mpriv_in));
478 1 : c = json_pack ("{s:s}", "test", "value");
479 1 : GNUNET_assert (NULL != c);
480 1 : TALER_CRYPTO_contract_encrypt_for_merge (&purse_pub,
481 : &cpriv,
482 : &mpriv_in,
483 : c,
484 : &econtract,
485 : &econtract_size);
486 1 : json_decref (c);
487 1 : c = TALER_CRYPTO_contract_decrypt_for_merge (&cpriv,
488 : &purse_pub,
489 : econtract,
490 : econtract_size,
491 : &mpriv_out);
492 1 : GNUNET_free (econtract);
493 1 : if (NULL == c)
494 0 : return 1;
495 1 : json_decref (c);
496 1 : if (0 != GNUNET_memcmp (&mpriv_in,
497 : &mpriv_out))
498 0 : return 1;
499 1 : return 0;
500 : }
501 :
502 :
503 : static int
504 1 : test_attributes (void)
505 : {
506 : struct TALER_AttributeEncryptionKeyP key;
507 : void *eattr;
508 : size_t eattr_size;
509 : json_t *c;
510 :
511 1 : GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
512 : &key,
513 : sizeof (key));
514 1 : c = json_pack ("{s:s}", "test", "value");
515 1 : GNUNET_assert (NULL != c);
516 1 : TALER_CRYPTO_kyc_attributes_encrypt (&key,
517 : c,
518 : &eattr,
519 : &eattr_size);
520 1 : json_decref (c);
521 1 : c = TALER_CRYPTO_kyc_attributes_decrypt (&key,
522 : eattr,
523 : eattr_size);
524 1 : GNUNET_free (eattr);
525 1 : if (NULL == c)
526 : {
527 0 : GNUNET_break (0);
528 0 : return 1;
529 : }
530 1 : GNUNET_assert (0 ==
531 : strcmp ("value",
532 : json_string_value (json_object_get (c,
533 : "test"))));
534 1 : json_decref (c);
535 1 : return 0;
536 : }
537 :
538 :
539 : int
540 1 : main (int argc,
541 : const char *const argv[])
542 : {
543 : (void) argc;
544 : (void) argv;
545 1 : GNUNET_log_setup ("test-crypto",
546 : "WARNING",
547 : NULL);
548 1 : if (0 != test_high_level ())
549 0 : return 1;
550 1 : if (0 != test_planchets (0))
551 0 : return 2;
552 1 : if (0 != test_planchets (13))
553 0 : return 3;
554 1 : if (0 != test_exchange_sigs ())
555 0 : return 4;
556 1 : if (0 != test_merchant_sigs ())
557 0 : return 5;
558 1 : if (0 != test_contracts ())
559 0 : return 6;
560 1 : if (0 != test_attributes ())
561 0 : return 7;
562 1 : return 0;
563 : }
564 :
565 :
566 : /* end of test_crypto.c */
|