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