Compare commits

...

108 Commits

Author SHA1 Message Date
Christian Grothoff
8cbe16a220
fix refresh/link tests 2022-02-08 09:58:22 +01:00
Christian Grothoff
133cf76f0d
use 'NULL' 2022-02-08 00:15:15 +01:00
Christian Grothoff
7eb989b2df
-get melt and refresh-reveal to pass again 2022-02-08 00:12:56 +01:00
Christian Grothoff
17a30cbd70
-cleanups 2022-02-07 23:38:30 +01:00
Christian Grothoff
e27ff05e63
-fix config file name 2022-02-07 22:01:37 +01:00
Christian Grothoff
a8b683fe3f
only one helper must be OK 2022-02-07 21:55:07 +01:00
Christian Grothoff
b79457cec6
-style fixes 2022-02-07 21:45:40 +01:00
Christian Grothoff
a5b8244948
-wake clients if we have 0 dks 2022-02-07 15:40:21 +01:00
Christian Grothoff
271711ae64
run denom helper even with zero denoms, as we may be using the other cipher type only 2022-02-07 15:02:34 +01:00
Christian Grothoff
ca7fa98016
-fix config file names 2022-02-07 14:53:32 +01:00
Christian Grothoff
e35e89f14d
-fix FTBFS 2022-02-07 13:43:29 +01:00
Christian Grothoff
b84fb618c3
fix refreshes_reveal FTBFS 2022-02-07 13:41:55 +01:00
Christian Grothoff
169d684342
-towards CS in refresh (incomplete, FTBFS) 2022-02-07 13:23:20 +01:00
Christian Grothoff
b2e6fcae1a
fix DB API for generic blinded planchet storage 2022-02-07 13:14:25 +01:00
Christian Grothoff
b9ea075d61
get DB test to build 2022-02-07 12:42:27 +01:00
Christian Grothoff
c7c0beedd5
-rename fest 2022-02-07 12:35:00 +01:00
Christian Grothoff
fb9ba5b1d2
-rename fest 2022-02-07 12:33:35 +01:00
Christian Grothoff
0d03f55282
-clean up of crypto.c 2022-02-07 11:33:58 +01:00
Christian Grothoff
d850ed9ca1
-fix test_crypto 2022-02-07 11:23:53 +01:00
Christian Grothoff
adeca20fe2
-update .gitignore 2022-02-07 11:06:11 +01:00
Christian Grothoff
f7a1f41eee
-get testing to build 2022-02-07 11:01:54 +01:00
Christian Grothoff
3ed39955b6
-fix test_crypto ftbfs 2022-02-07 10:58:23 +01:00
Christian Grothoff
031e365814
fix FTBFS of main logic 2022-02-07 10:55:07 +01:00
Christian Grothoff
2164c36f0f
got testing_api_cmd_refresh to compile 2022-02-07 10:09:12 +01:00
Christian Grothoff
4a575f5044
-final changes from Dora 2022-02-07 08:50:41 +01:00
Christian Grothoff
5ff3189075
-fix recoup testing cmds 2022-02-06 20:04:36 +01:00
Christian Grothoff
62d8368b1b
-fix more FTBFS issues 2022-02-06 19:53:23 +01:00
Christian Grothoff
66abbcac3f
-fix more FTBFS issues 2022-02-06 19:44:05 +01:00
Christian Grothoff
e735475623
-work on refresh_common FTBFS 2022-02-06 19:00:01 +01:00
Christian Grothoff
f173296c3c
-fix refresh FTBFS 2022-02-06 18:39:28 +01:00
Christian Grothoff
57bbdb0997
-fix melt FTBFS 2022-02-06 18:35:08 +01:00
Christian Grothoff
cfa1283053
merge more improvements from Dora 2022-02-06 12:33:49 +01:00
Gian Demarmels
34a7f59060
fixed src util and other stuff 2022-02-05 23:42:17 +01:00
Gian Demarmels
9fc3b7a278
Merge branch 'master' of ssh://git.taler.net/exchange 2022-02-05 23:12:31 +01:00
Gian Demarmels
b280b1db04
fix src/util 2022-02-05 23:12:21 +01:00
Lucien Heuzeveldt
251f2b5987
implement csr max request elements 2022-02-05 22:46:36 +01:00
Lucien Heuzeveldt
5a47863caf
implemenent flexible csr http endpoint 2022-02-05 22:16:00 +01:00
Christian Grothoff
718ad3996f
-FTBFS 2022-02-05 20:40:39 +01:00
Gian Demarmels
e8740316a7
fixes to crypto.c changes 2022-02-05 20:22:55 +01:00
Christian Grothoff
41d132757b
-implement new client-side csr logic 2022-02-05 17:06:42 +01:00
Christian Grothoff
63da97630d
hyphentation rules for names 2022-02-05 08:57:49 +01:00
Gian Demarmels
f46dc9ea5e
Merge branch 'master' of ssh://git.taler.net/exchange 2022-02-05 00:33:16 +01:00
Gian Demarmels
c42376cf40
crypto implementation 2022-02-05 00:32:53 +01:00
Christian Grothoff
aea7fc36c3
-style fix 2022-02-05 00:13:51 +01:00
Christian Grothoff
d81a6c7cf2
-work on reveal 2022-02-05 00:12:58 +01:00
Christian Grothoff
41acdf11b8
make API actually workable, sketch out melt 2022-02-05 00:02:38 +01:00
Christian Grothoff
b30765c7d0
make API actually workable, sketch out melt 2022-02-04 23:58:41 +01:00
Christian Grothoff
cfc6c3fcd0
make API actually workable: 2022-02-04 23:09:19 +01:00
Christian Grothoff
d833966d52
-API work 2022-02-04 22:02:48 +01:00
Christian Grothoff
bd5a25aff2
-fix comment 2022-02-04 21:20:26 +01:00
Christian Grothoff
57dc3cd232
new API 2022-02-04 21:12:54 +01:00
Christian Grothoff
ed136c1f2d
sync 2022-02-04 20:02:16 +01:00
Gian Demarmels
30c92a9b9e
Merge branch 'master' of ssh://git.taler.net/exchange 2022-02-04 19:50:40 +01:00
Gian Demarmels
752c0aca43
uncrustify 2022-02-04 19:50:21 +01:00
Gian Demarmels
37f54d3e5d
exchangedb fix 2022-02-04 19:50:12 +01:00
Christian Grothoff
03fd154a69
messing with CS/RSA fixes 2022-02-04 19:30:15 +01:00
Lucien Heuzeveldt
7d2a1a596a
split .conf files into rsa and cs 2022-02-04 19:24:30 +01:00
Christian Grothoff
9d40bd5a1e
split tests by rsa/cs 2022-02-04 18:45:42 +01:00
Gian Demarmels
a67786078b
resolves merge conflicts 2022-02-04 16:50:32 +01:00
Gian Demarmels
8674f32aec
denomination CIPHER field per denom 2022-02-04 15:39:57 +01:00
Gian Demarmels
086cf05794
refactor TALER_coin_ev_hash 2022-02-04 15:37:34 +01:00
Gian Demarmels
2213012866
include denom_pub into coin_ev_hash 2022-02-04 15:37:34 +01:00
Gian Demarmels
be50c084f8
fixed nonce check, renamed WithdrawNonce 2022-02-04 15:37:33 +01:00
Gian Demarmels
ae5f082c75
repair nonce check 2022-02-04 15:37:33 +01:00
Gian Demarmels
bcc159de17
introduce new type for security module pubkeys 2022-02-04 15:37:32 +01:00
Christian Grothoff
3510f953b0
-make picky gcc happy 2022-02-04 15:37:32 +01:00
Lucien Heuzeveldt
8d85c8b5b6
implement feedback 2022-02-04 15:37:30 +01:00
Christian Grothoff
ea97729ba8
-scope needed 2022-02-04 15:36:51 +01:00
Lucien Heuzeveldt
74ce114b83
change TEH_keys_denomination_sign message parameter 2022-02-04 15:36:48 +01:00
Gian Demarmels
5b7e8f9ac5
refactoring 2022-02-04 15:36:11 +01:00
Lucien Heuzeveldt
daa7fdcfb1
implement spend 2022-02-04 15:36:10 +01:00
Gian Demarmels
9c2aefaa51
removed varargs 2022-02-04 15:36:08 +01:00
Lucien Heuzeveldt
9074e66ebc
implement withdraw (nonce reuse check missing) 2022-02-04 15:35:31 +01:00
Gian Demarmels
4c7aa09784
cleanup 2022-02-04 15:34:22 +01:00
Gian Demarmels
2d70c8c6d0
secmod CS sign implementation 2022-02-04 15:34:21 +01:00
Lucien Heuzeveldt
82405b0ce5
implement CS key handling and csr endpoint 2022-02-04 15:34:19 +01:00
Lucien Heuzeveldt
36f551ff33
set planchet detail cipher, add cipher checks 2022-02-04 15:33:14 +01:00
Lucien Heuzeveldt
106664ed0c
implement TALER_CRYPTO_helper_cs_r_derive and related tests 2022-02-04 15:33:13 +01:00
Lucien Heuzeveldt
875a8b397e
implement secmod cs derive R 2022-02-04 15:33:13 +01:00
Gian Demarmels
d1fd3a485b
revocation 2022-02-04 15:33:13 +01:00
Gian Demarmels
9d9d4413df
setup_key for cs secmod helper 2022-02-04 15:33:12 +01:00
Gian Demarmels
18db69be2d
initial cs_secmod implementation 2022-02-04 15:33:11 +01:00
Gian Demarmels
f239b01be1
secmod cs signatures implementation 2022-02-04 15:33:11 +01:00
Lucien Heuzeveldt
fbb6d03f69
fix const due to changes in TALER_planchet_prepare 2022-02-04 15:33:10 +01:00
Lucien Heuzeveldt
75eff1524a
clean up cs implementation 2022-02-04 15:33:10 +01:00
Lucien Heuzeveldt
cf4fd36cc4
remove varargs in cs crypto implementation 2022-02-04 15:33:09 +01:00
Gian Demarmels
4bcbd704df
utility functions 2022-02-04 15:33:09 +01:00
Gian Demarmels
ca247f6f58
fixed CS signatures and cleanup/refactoring 2022-02-04 15:33:09 +01:00
Lucien Heuzeveldt
3225566c93
implement exchange_api_csr 2022-02-04 15:33:07 +01:00
Gian Demarmels
db9b84970d
add sign and verify implementation 2022-02-04 15:31:50 +01:00
Gian Demarmels
5d2157a8f6
sign_blinded implementation 2022-02-04 15:31:49 +01:00
Gian Demarmels
f1ec1e70a0
implemented planchet_prepare for CS 2022-02-04 15:31:49 +01:00
Gian Demarmels
a02ab8f81b
added CS get R functionality and planchet setup 2022-02-04 15:31:48 +01:00
Gian Demarmels
385eb51e93
CS planchet create and withdraw create 2022-02-04 15:31:48 +01:00
Gian Demarmels
f3fb7c29e6
added CS data structures, implemented CS keypair 2022-02-04 15:31:45 +01:00
Christian Grothoff
0a459aeb13
fix hyphenation 2022-02-03 18:54:12 +01:00
Christian Grothoff
9780625e09
-more edits from Dora 2022-02-03 18:52:01 +01:00
Christian Grothoff
dbaf21c215
-fix amp 2022-02-03 16:00:45 +01:00
ms
71de8b1663
-corrections at cbdc-it + FIXMEs 2022-02-02 08:14:43 +01:00
Christian Grothoff
bde9bdb38d
-more fixes from Dora 2022-02-01 17:53:50 +01:00
Christian Grothoff
f7162e756c
diagramma 2022-02-01 12:36:21 +01:00
Christian Grothoff
a0dd2de662
luca 2022-02-01 11:32:28 +01:00
Christian Grothoff
fc397f2634
-corrections from Dora 2022-02-01 10:04:59 +01:00
Christian Grothoff
5ea4e5b122
corrections from Dora 2022-02-01 09:35:28 +01:00
Christian Grothoff
649c6b6f72
cbdc-it 2022-01-31 17:11:13 +01:00
Christian Grothoff
88f64e238c
cbdc - Italian edition 2022-01-31 16:16:23 +01:00
e6e0cabf08
test and hopefully fix JSON canonicalization 2022-01-27 20:25:40 +01:00
32f1276b8c
fix RFC 8785 JSON normalization 2022-01-27 15:29:55 +01:00
110 changed files with 13229 additions and 1367 deletions

18
.gitignore vendored
View File

@ -5,6 +5,8 @@
*.gcno
*.gcda
*.mo
*.blg
*.bbl
.dirstamp
m4/*.m4
doc/coverage/
@ -34,7 +36,8 @@ GRTAGS
GTAGS
*.swp
src/include/taler_error_codes.h
src/lib/test_exchange_api
src/testing/test_exchange_api_rsa
src/testing/test_exchange_api_cs
doc/doxygen/doxygen_sqlite3.db
src/auditor/taler-auditor-dbinit
src/auditor/taler-auditor-sign
@ -71,6 +74,9 @@ src/exchange-tools/taler-wire
src/exchangedb/perf-exchangedb
src/benchmark/taler-exchange-benchmark
src/benchmark/auditor.in
src/benchmark/exchange_benchmark_home/.local/share/taler/exchange-offline/
src/benchmark/exchange_benchmark_home/.local/share/taler/exchange-secmod-eddsa/
src/benchmark/exchange_benchmark_home/.local/share/taler/exchange-secmod-rsa/
src/benchmark/exchange_benchmark_home/.local/share/taler/exchange/live-keys/*
src/benchmark/exchange_benchmark_home/.local/share/taler/auditors/
src/benchmark/exchange_benchmark_home/.local/share/taler/auditor/
@ -110,9 +116,11 @@ doc/manual/manual.vr
doc/prebuilt/*
contrib/taler-exchange.tag
doxygen-doc/
src/testing/test_exchange_api_keys_cherry_picking
src/testing/test_exchange_api_keys_cherry_picking_cs
src/testing/test_exchange_api_keys_cherry_picking_rsa
src/auditor/taler-auditor-sync
src/auditor/taler-wire-auditor
src/auditor/generate_auditordb_home/
contrib/auditor-report.aux
contrib/auditor-report.log
contrib/auditor-report.tex
@ -120,8 +128,10 @@ contrib/auditor-report.pdf
src/bank-lib/taler-bank-transfer
src/bank-lib/test_bank_api_twisted
src/testing/test_exchange_api
src/testing/test_auditor_api
src/testing/test_exchange_api_overlapping_keys_bug
src/testing/test_auditor_api_cs
src/testing/test_auditor_api_rsa
src/testing/test_exchange_api_overlapping_keys_bug_cs
src/testing/test_exchange_api_overlapping_keys_bug_rsa
src/testing/test_exchange_api_home/.local/share/taler/exchange/revocations/
src/wire-plugins/test_wire_plugin_legacy_taler_bank
uncrustify.cfg

@ -1 +1 @@
Subproject commit b0dd85e8187f33a1f92dd5eb31082050d333e168
Subproject commit c12314df0f82e192c6829a9c6cf3e9663b586da1

1375
doc/cbdc-it/agsm-mod.bst Normal file

File diff suppressed because it is too large Load Diff

561
doc/cbdc-it/cbdc-it.bib Normal file
View File

@ -0,0 +1,561 @@
%% To be used with modified bibliography style agsm-mod + hyperref + natbib + italian babel
@article{Adrian,
author = {Adrian, Tobias and Mancini-Griffoli},
year = {2019},
title = {{The Rise of Digital Money}},
journal = {IMF Fintech Note},
volume = {19/01},
}
@article{Agarwal,
author = {Agarwal, Ruchir and Miles S. Kimball},
year = {2019},
title = {{Enabling Deep Negative Rates to Fight Recessions: A Guide}},
journal = {IMF Working Paper},
volume = {19/84},
}
@article{Agur,
author = {Agur, Itai and Anil Ari and Giovanni Dell'Ariccia},
year = {2019},
title = {{Designing Central Bank Digital Currencies}},
journal = {IMF Working Paper},
volume = {19/252},
}
@article{Allen,
author = {Allen, Sarah and Srđjan Čapkun and Ittay Eyal and Giulia Fanti and Bryan A. Ford and James Grimmelmann and Ari Juels and Kari Kostiainen and Sarah Meiklejohn and Andrew Miller and Eswar Prasad and Karl Wüst and Fan Zhang},
year = {2020},
title = {{Design Choices for Central Bank Digital Currency: Policy and Technical Considerations}},
journal = {NBER Working Paper},
volume = {27634},
}
@article{Alves,
author = {Alves, Tiago and Don Felton},
year = {2004},
title = {TrustZone: Integrated hardware and software security},
journal = {ARM IQ},
volume = {3},
number = {4},
pages = {18--24},
}
@article{AuerBoehme,
author = {Auer, Raphael and Rainer Böhme},
year = {2020},
title = {The technology of retail central bank digital currency},
journal = {BIS Quarterly Review},
month = {March},
pages = {85--96},
}
@article{AuerCornelli,
author = {Auer, Raphael and Giulio Cornelli and Jon Frost},
year = {2020},
title = {{Taking stock: ongoing retail CBDC projects}},
journal = {BIS Quarterly Review},
month = {March},
pages = {97--98},
}
@booklet{BIS,
author = {{Bank for International Settlements}},
year = {2018},
title = {{Central Bank Digital Currencies. Joint Report of the Committee on Payments and Market Infrastructures and Markets Committee}},
}
@booklet{BoE,
author = {{Bank of England}},
year = {2020},
title = {{Central Bank Digital Currency: Opportunities, Challenges and Design. Discussion Paper}},
month = {March},
}
@article{Baiocchi,
author = {Baiocchi, Giovanni and Walter Distaso},
year = {2003},
title = {{GRETL: Econometric Software for the GNU Generation}},
journal = {Journal of Applied Econometrics},
volume = {18},
pages = {105-110},
}
@article{Bech,
author = {Bech, Morten and Rodney Garratt},
year = {2017},
title = {Central bank cryptocurrencies},
journal = {BIS Quarterly Review},
month = {September},
pages = {55--70},
}
@article{Berentsen,
author = {Berentsen, Aleksander and Fabian Schär},
year = {2018},
title = {{The Case for Central Bank Electronic Money and the Non-case for Central Bank Cryptocurrencies}},
journal = {Federal Reserve Bank of St. Louis Review},
volume = {100},
number = {2},
pages = {97--106},
}
@article{Bernstein2020,
author = {Bernstein, Daniel J. and Tanja Lange},
year = {2020},
title = {{eBACS: ECRYPT Benchmarking of Cryptographic Systems}},
url = {\url{https://bench.cr.yp.to}, consultato il 17 marzo 2020},
}
@article{Bernstein2012,
author = {Bernstein, Daniel J. and Niels Duif and Tanja Lange and Peter Schwabe and Bo-Yin Yang},
year = {2012},
title = {High-speed high-security signatures},
journal = {Journal of Cryptographic Engineering},
volume = {2},
pages = {77--89},
}
@InCollection{Bindseil,
author = {Bindseil, Ulrich},
year = {2020},
title = {{Tiered CBDC and the financial system}},
publisher = {European Central Bank},
series = {ECB Working Paper},
number = {2351},
month = {January},
}
@article{Boar,
author = {Boar, Codruta and Henry Holden and Amber Wadsworth},
year = {2020},
title = {Impending arrival - a sequel to the survey on central bank digital currency},
journal = {BIS Papers},
volume = {107},
}
@article{Boneh,
author = {Boneh, Dan},
year = {1999},
title = {{Twenty Years of Attacks on the RSA Cryptosystem}},
journal = {Notices of the AMS},
volume = {42},
number = {2},
pages = {202--213},
}
@InCollection{Bordo,
author = {Bordo, Michael D. and Andrew T. Levin},
year = {2017},
title = {Central bank digital currency and the future of monetary policy},
publisher = {National Bureau of Economic Research},
series = {NBER Working Paper Series},
number = {23711},
}
@article{Brunnermeier,
author = {Brunnermeier, Markus and Dirk Niepelt},
year = {2019},
title = {{On the Equivalence of Private and Public Money}},
journal = {Journal of Monetary Economics},
volume = {106},
pages = {27--41},
}
@article{Buiter,
author = {Buiter, Willem H. and Nikolaos Panigirtzoglou},
year = {2003},
title = {{Overcoming the Zero Bound on Nominal Interest Rates with Negative Interest on Currency: Gesell's Solution}},
journal = {The Economic Journal},
volume = {113},
number = {490},
pages = {723--746},
}
@InCollection{Bullmann,
author = {Bullmann, Dirk and Jonas Klemm and Andrea Pinna},
year = {2019},
title = {In search for stability in crypto-assets: are stablecoins the solution?},
publisher = {European Central Bank},
series = {ECB Occasional Paper Series},
number = {230},
}
@inproceedings{Camenisch2007,
author = {Camenisch, Jan and Aanna Lysyanskaya and Mira Meyerovich},
year = {2007},
title = {{Endorsed E-Cash}},
booktitle = {\textit{2007 IEEE Symposium on Security and Privacy (SP'07)}},
month = {May},
pages = {101--115},
}
@inproceedings{Camenisch2005,
author = {Camenisch, Jan and Susan Hohenberger and Anna Lysyanskaya},
year = {2005},
title = {{Compact E-Cash}},
booktitle = {\textit{Advances in Cryptology -- EUROCRYPT 2005: 24th Annual International Conference on the Theory and Applications of Cryptographic Techniques}},
address = {Aarhus, Denmark},
month = {May},
day = {22-26},
editor = {Ed. di Ronald Cramer},
publisher = {Springer-Verlag Berlin Heidelberg},
}
@inproceedings{Canard,
author = {Canard, Sébastien and Aline Gouget},
year = {2007},
title = {Divisible e-cash systems can be truly anonymous},
booktitle = {\textit{Annual International Conference on the Theory and Applications of Cryptographic Techniques}},
pages = {482--497},
}
@misc{CCC,
author = {{CCC e.V.}},
year = {2017},
title = {{Chaos Computer Club hacks e-motor charging stations}},
howpublished = {34c3},
}
@article{Chapman,
author = {Chapman, James and Rodney Garratt and Scott Hendry and Andrew McCormack and Wade McMahon},
year = {2017},
title = {{Project Jasper: Are Distributed Wholesale Payment Systems Feasible Yet?}},
journal = {Financial System Review},
publisher = {Bank of Canada},
month = {June},
pages = {59--69},
}
@inproceedings{Chaum1983,
author = {Chaum, David},
year = {1983},
title = {Blind signatures for untraceable payments},
booktitle = {\textit{Advances in Cryptology: Proceedings of Crypto `82}},
pages = {199--203},
}
@inproceedings{Chaum1990,
author = {Chaum, David and Amos Fiat and Moni Naor},
year = {1990},
title = {Untraceable electronic cash},
booktitle = {\textit{Advances in Cryptology: Proceedings of CRYPTO '88}},
pages = {319--327},
}
@inproceedings{Danezis,
author = {Danezis, George and Sarah Meiklejohn},
year = {2016},
title = {{Centrally Banked Cryptocurrencies}},
booktitle = {\textit{23nd Annual Network and Distributed System Security Symposium, NDSS2016}},
address = {San Diego, California, USA},
month = {February},
day = {21--24},
publisher = {The Internet Society},
}
@article{Diffie,
author = {Diffie, Whitfield and Martin Hellmann},
year = {1976},
title = {{New Directions in Cryptography}},
journal = {IEEE Trans. on Inf. Theory, IT-22},
pages = {644--654},
}
@phdthesis{Dold,
author = {Dold, Florian},
year = {2019},
title = {{The GNU Taler System: Practical and Provably Secure Electronic Payments. PhD Thesis}},
school = {University of Rennes 1},
}
@article{ECB,
author = {{European Central Bank}},
year = {2019},
title = {Exploring anonymity in central bank digital currencies},
journal = {In Focus},
number = {4},
month = {December},
}
@inproceedings{Fuchsbauer,
author = {Fuchsbauer, Georg and David Pointcheval and Damien Vergnaud},
year = {2009},
title = {Transferable constant-size fair e-cash},
booktitle = {International Conference on Cryptology and Network Security},
publisher = {Springer-Verlag Berlin Heidelberg},
pages = {226--247},
}
@inproceedings{Garcia,
author = {Garcia, Flavio and Gerhard de Koning Gans and Ruben Muijrers and Peter van Rossum and Roel Verdult and Ronny Wichers Schreur and Bart Jacobs},
year = {2008},
title = {{Dismantling MIFARE Classic}},
booktitle = {\textit{European Symposium on Research in Computer Security}},
}
@article{Garratt,
author = {Garratt, Rod and Michael Lee and Brendan Malone and Antoine Martin},
year = {2020},
title = {{Token- or Account-Based? A Digital Currency Can Be Both}},
journal = {Liberty Street Economics},
publisher = {Federal Reserve Bank of New York},
month = {August},
day = {12},
}
@article{Goodfriend,
author = {Goodfriend, Marvin},
year = {2000},
title = {{Overcoming the Zero Bound on Interest Rate Policy}},
journal = {Journal of Money, Credit, and Banking},
volume = {32},
number = {4},
pages = {1007--1035},
}
@article{Johnston,
author = {Johnston, Casey},
year = {2010},
title = {PS3 hacked through poor cryptography implementation},
journal = {Ars Technica},
month = {December},
day = {30},
}
@Misc{Jordan,
note = {Discorso in occasione del 30º anniversario del Centro di scienze economiche (WWZ) e dellAssociazione degli economisti basilesi (VBÖ)},
author = {Jordan, Thomas J.},
year = {2019},
title = {Valute, moneta e token digitali},
publisher = {University of Basel},
month = {September},
howpublished = {\url{https://www.snb.ch/it/mmr/speeches/id/ref_20190905_tjn/source/ref_20190905_tjn.it.pdf}},
}
@article{Kahn2009,
author = {Kahn, Charles M. and William Roberds},
year = {2009},
title = {{Why Pay? An Introduction to Payments Economics}},
journal = {Journal of Financial Intermediation},
number = {18},
pages = {1--23},
}
@article{Kahn2005,
author = {Kahn, Charles M. and James McAndrews and William Roberds},
year = {2005},
title = {{Money is Privacy}},
journal = {International Economic Review},
volume = {46},
number = {2},
pages = {377--399},
}
@article{Kasper,
author = {Kasper, Timo and Michael Silbermann and Christof Paar},
year = {2010},
title = {All you can eat or breaking a real-world contactless payment system},
journal = {Financial Cryptography and Data Security, Lecture Notes in Computer Science},
volume = {6052},
pages = {343--50},
}
@inproceedings{Katzenbeisser,
author = {Katzenbeisser, Stefan and Ünal Kocabaş and Vladimir Rožić and Ahmad-Reza Sadeghi and Ingrid Verbauwhede and Christian Wachsmann},
year = {2012},
title = {{PUFs: Myth, Fact or Busted? A Security Evaluation of Physically Unclonable Functions (PUFs) Cast in Silicon}},
booktitle = {\textit{Cryptographic Hardware and Embedded Systems -- CHES 2012. Lecture Notes in Computer Science}},
volume = {7428},
pages = {283--301},
}
@book{Keynes,
author = {Keynes, John Maynard},
year = {1936},
title = {The General Theory of Employment, Interest and Money},
publisher = {Macmillan},
}
@article{Kiff,
author = {Kiff, John and Jihad Alwazir and Sonja Davidovic and Aquiles Farias and Ashraf Khan and Tanai Khiaonarong and Majid Malaika and Hunter Monroe and Nobu Sugimoto and Hervé Tourpe and Peter Zhou},
year = {2020},
title = {{A Survey of Research on Retail Central Bank Digital Currency}},
journal = {IMF Working Paper},
volume = {20/104},
}
@InCollection{Kumhof,
author = {Kumhof, Michael and Clare Noone},
year = {2018},
title = {Central bank digital currencies - design principles and balance sheet implications},
publisher = {Bank of England},
series = {Staff Working Paper},
number = {725},
}
@inproceedings{Lapid,
author = {Lapid, Ben and Avishai Wool},
year = {2018},
title = {{Cache-Attacks on the ARM TrustZone Implementations of AES-256 and AES-256-GCM via GPU-Based Analysis}},
booktitle = {\textit{International Conference on Selected Areas in Cryptography. Lecture Notes in Computer Science}},
volume = {11349},
}
@article{Lerner,
author = {Lerner, Josh and Jean Tirole},
year = {2005},
title = {{The Scope of Open Source Licensing}},
journal = {Journal of Law, Economics \& Organization},
volume = {21},
pages = {20-56},
}
@misc{Libra,
author = {{Libra Association}},
year = {2020},
title = {{Libra White Paper v2.0}},
url = {\url{https://libra.org/en-US/white-paper}},
}
@inproceedings{Lim,
author = {Lim, Chae Hoon and Phil Joong Lee},
year = {1997},
title = {A key recovery attack on discrete log-based schemes using a prime order subgroup},
booktitle = {\textit{CRYPTO 1997. Lecture Notes in Computer Science}},
volume = {1294},
}
@InCollection{Lyons,
author = {Lyons, Richard K. and Ganesh Viswanath-Natraj},
year = {2020},
title = {{What Keeps Stablecoins Stable?}},
publisher = {National Bureau of Economic Research},
series = {NBER Working Paper Series},
number = {27136},
month = {May},
}
@article{Mancini-Griffoli,
author = {Mancini-Griffoli and Maria Soledad Martinez Peria and Itai Agur and Anil Ari and John Kiff and Adina Popescu and Celine Rochon},
year = {2018},
title = {{Casting Light on Central Bank Digital Currency}},
journal = {IMF Staff Discussion Notes},
volume = {18/08},
publisher = {International Monetary Fund},
}
@misc{Nakamoto,
author = {Nakamoto, Satoshi},
year = {2008},
title = {{Bitcoin: A Peer-to-Peer Electronic Cash System}},
url = {\url{https://www.bitcoin.com/bitcoin.pdf}},
}
@book{Narayanan,
author = {Narayanan, Arvind and Joseph Bonneau and Edward Felten and Andrew Miller and Steven Goldfeder},
year = {2016},
title = {Bitcoin and Cryptocurrency Technologies: A Comprehensive Introduction},
publisher = {Princeton University Press},
}
@misc{Niepelt,
author = {Niepelt, Dirk},
year = {2020},
title = {Digital money and central bank digital currency: An executive summary for policymakers},
howpublished = {\url{https://voxeu.org/article/digital-money-and-central-bank-digital-currency-executive-summary}},
}
@inproceedings{Okamoto,
author = {Okamoto, Tatsuaki},
year = {1995},
title = {{An Efficient Divisible Electronic Cash Scheme}},
booktitle = {\textit{Advances in Cryptology --- CRYPT0'95: 15th Annual International Cryptology Conference Santa Barbara, California, USA, 27--31 agosto, 1995 Proceedings}},
editor = {Ed. di Don Coppersmith},
publisher = {Springer-Verlag Berlin Heidelberg},
pages = {438--451},
}
@article{Pinto,
author = {Pinto, S. and N. Santos},
year = {2019},
title = {{Demystifying ARM TrustZone: A Comprehensive Survey}},
journal = {ACM Computing Surveys},
volume = {51},
number = {6},
month = {January},
pages = {1--31}
}
@article{Rivest,
author = {Rivest, Ronald L. and Adi Shamir and Leonard Adleman},
year = {1978},
title = {{A Method for Obtaining Digital Signatures and Public Key Cryptosystems}},
journal = {Comm. ACM},
volume = {21},
number = {2},
}
@book{Solove,
author = {Solove, Daniel J.},
year = {2011},
title = {Nothing to Hide: The false tradeoff between privacy and security},
publisher = {New Haven \& London: Yale University Press},
}
@article{Soukup,
author = {Soukup, Michael and Bruno Muff},
year = {2007},
title = {{Die Postcard lässt sich fälschen}},
journal = {Sonntagszeitung},
month = {April},
day = {22},
}
@article{Stallman,
author = {Stallman, Richard},
year = {1985},
title = {{The GNU manifesto}},
journal = {Dr. Dobb's Journal of Software Tools},
volume = {10},
number = {3},
pages = {30--35},
}
@TechReport{Riksbank,
author = {{Sveriges Riksbank}},
year = {2020},
title = {{The Riksbank's e-krona project}},
month = {February},
institution = {Sveriges Riksbank},
url = {\url{https://www.riksbank.se/globalassets/media/rapporter/e-krona/2019/the-riksbanks-e-krona-pilot.pdf}},
}
@misc{Wojtczuk,
author = {Wojtczuk, Rafal and Joanna Rutkowska},
year = {2009},
title = {{Attacking Intel Trusted Execution Technology}},
howpublished = {BlackHat-DC 2009},
}
@article{Yalta2010,
author = {Yalta, A. Talha and A. Yasemin Yalta},
year = {2010},
title = {{Should Economists Use Open Source Software for Doing Research?}},
journal = {Computational Economics},
volume = {35},
pages = {371--394},
}
@article{Yalta2008,
author = {Yalta, A. Talha and Riccardo Lucchetti},
year = {2008},
title = {{The GNU/Linux Platform and Freedom Respecting Software for Economists}},
journal = {Journal of Applied Econometrics},
volume = {23},
pages = {279-286},
}

1303
doc/cbdc-it/cbdc-it.tex Normal file

File diff suppressed because it is too large Load Diff

566
doc/cbdc-it/cbdc.bib Normal file
View File

@ -0,0 +1,566 @@
@article{Adrian,
author = {Adrian, Tobias and Tommaso Mancini-Griffoli},
year = {2019},
title = {The Rise of Digital Money},
journal = {IMF Fintech Note},
volume = {19/01},
}
@article{Agarwal,
author = {Agarwal, Ruchir and Miles S. Kimball},
year = {2019},
title = {Enabling Deep Negative Rates to Fight Recessions: A Guide},
journal = {IMF Working Paper},
volume = {19/84},
}
@article{Agur,
author = {Agur, Itai and Anil Ari and Giovanni Dell'Ariccia},
year = {2019},
title = {Designing Central Bank Digital Currencies},
journal = {IMF Working Paper},
volume = {19/252},
}
@article{Allen,
author = {Allen, Sarah and Srđjan Čapkun and Ittay Eyal and Giulia Fanti and Bryan A. Ford and James Grimmelmann and Ari Juels and Kari Kostiainen and Sarah Meiklejohn and Andrew Miller and Eswar Prasad and Karl Wüst and Fan Zhang},
year = {2020},
title = {Design Choices for Central Bank Digital Currency: Policy and Technical Considerations},
journal = {NBER Working Paper},
volume = {27634},
}
@article{Alves,
author = {Alves, Tiago and Don Felton},
year = {2004},
title = {TrustZone: Integrated hardware and software security},
journal = {ARM IQ},
volume = {3},
number = {4},
pages = {18--24},
}
@article{AuerBoehme,
author = {Auer, Raphael and Rainer Böhme},
year = {2020},
title = {The technology of retail central bank digital currency},
journal = {BIS Quarterly Review},
month = {March},
pages = {85--96},
}
@article{AuerCornelli,
author = {Auer, Raphael and Giulio Cornelli and Jon Frost},
year = {2020},
title = {Taking stock: ongoing retail {CBDC} projects},
journal = {BIS Quarterly Review},
month = {March},
pages = {97--98},
}
@booklet{BIS,
author = {{Bank for International Settlements}},
year = {2018},
title = {Central Bank Digital Currencies. Joint Report of the Committee on Payments and Market Infrastructures and Markets Committee},
}
@booklet{BoE,
author = {{Bank of England}},
year = {2020},
title = {Central Bank Digital Currency: Opportunities, Challenges and Design. Discussion Paper},
month = {March},
}
@article{Baiocchi,
author = {Baiocchi, Giovanni and Walter Distaso},
year = {2003},
title = {{GRETL}: Econometric Software for the {GNU} Generation},
journal = {Journal of Applied Econometrics},
volume = {18},
pages = {105-110},
}
@article{Bech,
author = {Bech, Morten and Rodney Garratt},
year = {2017},
title = {Central bank cryptocurrencies},
journal = {BIS Quarterly Review},
month = {September},
pages = {55--70},
}
@article{Berentsen,
author = {Berentsen, Aleksander and Fabian Schär},
year = {2018},
title = {The Case for Central Bank Electronic Money and the Non-case for Central Bank Cryptocurrencies},
journal = {Federal Reserve Bank of St. Louis Review},
volume = {100},
number = {2},
pages = {97--106},
}
@article{Bernstein2020,
author = {Bernstein, Daniel J. and Tanja Lange},
year = {2020},
title = {{eBACS}: {ECRYPT} Benchmarking of Cryptographic Systems},
url = {\url{https://bench.cr.yp.to}, accessed 17 March 2020},
}
@article{Bernstein2012,
author = {Bernstein, Daniel J. and Niels Duif and Tanja Lange and Peter Schwabe and Bo-Yin Yang},
year = {2012},
title = {High-speed high-security signatures},
journal = {Journal of Cryptographic Engineering},
volume = {2},
pages = {77--89},
}
@InCollection{Bindseil,
author = {Bindseil, Ulrich},
year = {2020},
title = {Tiered {CBDC} and the financial system},
publisher = {European Central Bank},
series = {ECB Working Paper},
number = {2351},
month = {January},
}
@article{Boar,
author = {Boar, Codruta and Henry Holden and Amber Wadsworth},
year = {2020},
title = {Impending arrival - a sequel to the survey on central bank digital currency},
journal = {BIS Papers},
volume = {107},
}
@article{Boneh,
author = {Boneh, Dan},
year = {1999},
title = {Twenty Years of Attacks on the {RSA} Cryptosystem},
journal = {Notices of the AMS},
volume = {42},
number = {2},
pages = {202--213},
}
@InCollection{Bordo,
author = {Bordo, Michael D. and Andrew T. Levin},
year = {2017},
title = {Central bank digital currency and the future of monetary policy},
publisher = {National Bureau of Economic Research},
series = {NBER Working Paper Series},
number = {23711},
}
@article{Brunnermeier,
author = {Brunnermeier, Markus and Dirk Niepelt},
year = {2019},
title = {On the Equivalence of Private and Public Money},
journal = {Journal of Monetary Economics},
volume = {106},
pages = {27--41},
}
@article{Buiter,
author = {Buiter, Willem H. and Nikolaos Panigirtzoglou},
year = {2003},
title = {Overcoming the Zero Bound on Nominal Interest Rates with Negative Interest on Currency: Gesell's Solution},
journal = {The Economic Journal},
volume = {113},
number = {490},
pages = {723--746},
}
@InCollection{Bullmann,
author = {Bullmann, Dirk and Jonas Klemm and Andrea Pinna},
year = {2019},
title = {In search for stability in crypto-assets: are stablecoins the solution?},
publisher = {European Central Bank},
series = {ECB Occasional Paper Series},
number = {230},
}
@inproceedings{Camenisch2007,
author = {Camenisch, Jan and Aanna Lysyanskaya and Mira Meyerovich},
year = {2007},
title = {Endorsed E-Cash},
booktitle = {2007 IEEE Symposium on Security and Privacy (SP'07)},
month = {May},
pages = {101--115},
}
@inproceedings{Camenisch2005,
author = {Camenisch, Jan and Susan Hohenberger and Anna Lysyanskaya},
year = {2005},
title = {Compact E-Cash},
booktitle = {Advances in Cryptology -- EUROCRYPT 2005: 24th Annual International Conference on the Theory and Applications of Cryptographic Techniques},
address = {Aarhus, Denmark},
month = {May},
day = {22-26},
editor = {Ed. by Ronald Cramer},
publisher = {Springer-Verlag Berlin Heidelberg},
}
@inproceedings{Canard,
author = {Canard, Sébastien and Aline Gouget},
year = {2007},
title = {Divisible e-cash systems can be truly anonymous},
booktitle = {Annual International Conference on the Theory and Applications of Cryptographic Techniques},
pages = {482--497},
}
@misc{CCC,
author = {{CCC e.V.}},
year = {2017},
title = {Chaos Computer Club hacks e-motor charging stations},
howpublished = {34c3},
}
@article{Chapman,
author = {Chapman, James and Rodney Garratt and Scott Hendry and Andrew McCormack and Wade McMahon},
year = {2017},
title = {Project {J}asper: Are Distributed Wholesale Payment Systems Feasible Yet?},
journal = {Financial System Review},
publisher = {Bank of Canada},
month = {June},
pages = {59--69},
}
@inproceedings{Chaum1983,
author = {Chaum, David},
year = {1983},
title = {Blind signatures for untraceable payments},
booktitle = {Advances in Cryptology: Proceedings of Crypto `82},
pages = {199--203},
}
@inproceedings{Chaum1990,
author = {Chaum, David and Amos Fiat and Moni Naor},
year = {1990},
title = {Untraceable electronic cash},
booktitle = {Advances in Cryptology: Proceedings of CRYPTO '88},
pages = {319--327},
}
@inproceedings{Danezis,
author = {Danezis, George and Sarah Meiklejohn},
year = {2016},
title = {Centrally Banked Cryptocurrencies},
booktitle = {23nd Annual Network and Distributed System Security Symposium, NDSS2016},
address = {San Diego, California, USA},
month = {February},
day = {21--24},
publisher = {The Internet Society},
}
@article{Diffie,
author = {Diffie, Whitfield and Martin Hellmann},
year = {1976},
title = {New Directions in Cryptography},
journal = {IEEE Trans. on Inf. Theory, IT-22},
pages = {644--654},
}
@phdthesis{Dold,
author = {Dold, Florian},
year = {2019},
title = {The {GNU} {T}aler System: Practical and Provably Secure Electronic Payments. PhD Thesis},
school = {University of Rennes 1},
}
@article{ECB,
author = {{European Central Bank}},
year = {2019},
title = {Exploring anonymity in central bank digital currencies},
journal = {In Focus},
number = {4},
month = {December},
}
@inproceedings{Fuchsbauer,
author = {Fuchsbauer, Georg and David Pointcheval and Damien Vergnaud},
year = {2009},
title = {Transferable constant-size fair e-cash},
booktitle = {International Conference on Cryptology and Network Security},
publisher = {Springer-Verlag Berlin Heidelberg},
pages = {226--247},
}
@inproceedings{Garcia,
author = {Garcia, Flavio and Gerhard de Koning Gans and Ruben Muijrers and Peter van Rossum and Roel Verdult and Ronny Wichers Schreur and Bart Jacobs},
year = {2008},
title = {Dismantling MIFARE Classic},
booktitle = {European Symposium on Research in Computer Security},
}
@article{Garratt,
author = {Garratt, Rod and Michael Lee and Brendan Malone and Antoine Martin},
year = {2020},
title = {Token- or Account-Based? A Digital Currency Can Be Both},
journal = {Liberty Street Economics},
publisher = {Federal Reserve Bank of New York},
month = {August},
day = {12},
}
@article{Goodfriend,
author = {Goodfriend, Marvin},
year = {2000},
title = {Overcoming the Zero Bound on Interest Rate Policy},
journal = {Journal of Money, Credit, and Banking},
volume = {32},
number = {4},
pages = {1007--1035},
}
@article{Johnston,
author = {Johnston, Casey},
year = {2010},
title = {PS3 hacked through poor cryptography implementation},
journal = {Ars Technica},
month = {December},
day = {30},
}
@Misc{Jordan,
note = {Speech given at the 30th anniversary of the WWZ and VBÖ},
author = {Jordan, Thomas J.},
year = {2019},
title = {Currencies, money and digital tokens},
publisher = {University of Basel},
month = {September},
howpublished = {\url{https://www.snb.ch/en/mmr/speeches/id/ref\_20190905\_tjn/source/ref\_20190905\_tjn.en.pdf}},
}
@article{Kahn2009,
author = {Kahn, Charles M. and William Roberds},
year = {2009},
title = {Why Pay? An Introduction to Payments Economics},
journal = {Journal of Financial Intermediation},
number = {18},
pages = {1--23},
}
@article{Kahn2005,
author = {Kahn, Charles M. and James McAndrews and William Roberds},
year = {2005},
title = {Money is Privacy},
journal = {International Economic Review},
volume = {46},
number = {2},
pages = {377--399},
}
@article{Kasper,
author = {Kasper, Timo and Michael Silbermann and Christof Paar},
year = {2010},
title = {All you can eat or breaking a real-world contactless payment system},
journal = {Financial Cryptography and Data Security, Lecture Notes in Computer Science},
volume = {6052},
pages = {343--50},
}
@inproceedings{Katzenbeisser,
author = {Katzenbeisser, Stefan and Ünal Kocabaş and Vladimir Rožić and Ahmad-Reza Sadeghi and Ingrid Verbauwhede and Christian Wachsmann},
year = {2012},
title = {{PUF}s: Myth, Fact or Busted? A Security Evaluation of Physically Unclonable Functions ({PUF}s) Cast in Silicon},
booktitle = {Cryptographic Hardware and Embedded Systems -- CHES 2012. Lecture Notes in Computer Science},
volume = {7428},
pages = {283--301},
}
@book{Keynes,
author = {Keynes, John Maynard},
year = {1936},
title = {The General Theory of Employment, Interest and Money},
publisher = {Macmillan},
}
@article{Kiff,
author = {Kiff, John and Jihad Alwazir and Sonja Davidovic and Aquiles Farias and Ashraf Khan and Tanai Khiaonarong and Majid Malaika and Hunter Monroe and Nobu Sugimoto and Hervé Tourpe and Peter Zhou},
year = {2020},
title = {A Survey of Research on Retail Central Bank Digital Currency},
journal = {IMF Working Paper},
volume = {20/104},
}
@InCollection{Kumhof,
author = {Kumhof, Michael and Clare Noone},
year = {2018},
title = {Central bank digital currencies - design principles and balance sheet implications},
publisher = {Bank of England},
series = {Staff Working Paper},
number = {725},
}
@inproceedings{Lapid,
author = {Lapid, Ben and Avishai Wool},
year = {2018},
title = {Cache-Attacks on the {ARM} TrustZone Implementations of {AES}-256 and {AES}-256-{GCM} via {GPU}-Based Analysis},
booktitle = {International Conference on Selected Areas in Cryptography. Lecture Notes in Computer Science},
volume = {11349},
}
@article{Lerner,
author = {Lerner, Josh and Jean Tirole},
year = {2005},
title = {The Scope of Open Source Licensing},
journal = {Journal of Law, Economics \& Organization},
volume = {21},
pages = {20-56},
}
@misc{Libra,
author = {{Libra Association}},
year = {2020},
title = {Libra White Paper v2.0},
url = {\url{https://libra.org/en-US/white-paper}},
}
@inproceedings{Lim,
author = {Lim, Chae Hoon and Phil Joong Lee},
year = {1997},
title = {A key recovery attack on discrete log-based schemes using a prime order subgroup},
booktitle = {CRYPTO 1997. Lecture Notes in Computer Science},
volume = {1294},
}
@InCollection{Lyons,
author = {Lyons, Richard K. and Ganesh Viswanath-Natraj},
year = {2020},
title = {What Keeps Stablecoins Stable?},
publisher = {National Bureau of Economic Research},
series = {NBER Working Paper Series},
number = {27136},
month = {May},
}
@article{Mancini-Griffoli,
author = {Mancini-Griffoli, Tommaso and Maria Soledad Martinez Peria and Itai Agur and Anil Ari and John Kiff and Adina Popescu and Celine Rochon},
year = {2018},
title = {Casting Light on Central Bank Digital Currency},
journal = {IMF Staff Discussion Notes},
volume = {18/08},
publisher = {International Monetary Fund},
}
@misc{Nakamoto,
author = {Nakamoto, Satoshi},
year = {2008},
title = {Bitcoin: A Peer-to-Peer Electronic Cash System},
url = {\url{https://www.bitcoin.com/bitcoin.pdf}},
}
@book{Narayanan,
author = {Narayanan, Arvind and Joseph Bonneau and Edward Felten and Andrew Miller and Steven Goldfeder},
year = {2016},
title = {Bitcoin and Cryptocurrency Technologies: A Comprehensive Introduction},
publisher = {Princeton University Press},
}
@misc{Niepelt,
author = {Niepelt, Dirk},
year = {2020},
title = {Digital money and central bank digital currency: An executive summary for policymakers},
url = {https://voxeu.org/article/digital-money-and-central-bank-digital-currency-executive-summary},
}
@inproceedings{Okamoto,
author = {Okamoto, Tatsuaki},
year = {1995},
title = {An Efficient Divisible Electronic Cash Scheme},
booktitle = {Advances in Cryptology --- CRYPT0'95: 15th Annual International Cryptology Conference Santa Barbara, California, USA, August 27--31, 1995 Proceedings},
editor = {Ed. by Don Coppersmith},
publisher = {Springer-Verlag Berlin Heidelberg},
pages = {438--451},
}
@article{Pinto,
author = {Pinto, S. and N. Santos},
year = {2019},
title = {Demystifying {ARM} TrustZone: A Comprehensive Survey},
journal = {ACM Computing Surveys},
volume = {51},
number = {6},
month = {January},
pages = {1--31}
}
@article{Rivest,
author = {Rivest, Ronald L. and Adi Shamir and Leonard Adleman},
year = {1978},
title = {A Method for Obtaining Digital Signatures and Public Key Cryptosystems},
journal = {Comm. ACM},
volume = {21},
number = {2},
}
@book{Solove,
author = {Solove, Daniel J.},
year = {2011},
title = {Nothing to Hide: The false tradeoff between privacy and security},
publisher = {New Haven \& London: Yale University Press},
}
@article{Soukup,
author = {Soukup, Michael and Bruno Muff},
year = {2007},
title = {Die {P}ostcard lässt sich fälschen},
journal = {Sonntagszeitung},
month = {April},
day = {22},
}
@article{Stallman,
author = {Stallman, Richard},
year = {1985},
title = {The {GNU} manifesto},
journal = {Dr. Dobb's Journal of Software Tools},
volume = {10},
number = {3},
pages = {30--35},
}
@TechReport{Riksbank,
author = {{Sveriges Riksbank}},
year = {2020},
title = {The {R}iksbank's e-krona project},
month = {Feb},
institution = {Sveriges Riksbank},
url = {\url{https://www.riksbank.se/globalassets/media/rapporter/e-krona/2019/the-riksbanks-e-krona-pilot.pdf}},
}
@misc{Wojtczuk,
author = {Wojtczuk, Rafal and Joanna Rutkowska},
year = {2009},
title = {Attacking {I}ntel Trusted Execution Technology},
howpublished = {BlackHat-DC 2009},
}
@article{Yalta2010,
author = {Yalta, A. Talha and A. Yasemin Yalta},
year = {2010},
title = {Should Economists Use Open Source Software for Doing Research?},
journal = {Computational Economics},
volume = {35},
pages = {371--394},
}
@article{Yalta2008,
author = {Yalta, A. Talha and Riccardo Lucchetti},
year = {2008},
title = {The {GNU/L}inux Platform and Freedom Respecting Software for Economists},
journal = {Journal of Applied Econometrics},
volume = {23},
pages = {279-286},
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 119 KiB

BIN
doc/cbdc-it/graphics-it.odp Normal file

Binary file not shown.

View File

@ -106,6 +106,7 @@ fee_withdraw = TESTKUDOS:0.01
fee_deposit = TESTKUDOS:0.01
fee_refresh = TESTKUDOS:0.01
fee_refund = TESTKUDOS:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_kudos_ct_10]
@ -117,6 +118,7 @@ fee_withdraw = TESTKUDOS:0.01
fee_deposit = TESTKUDOS:0.01
fee_refresh = TESTKUDOS:0.03
fee_refund = TESTKUDOS:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_kudos_1]
@ -128,6 +130,7 @@ fee_withdraw = TESTKUDOS:0.02
fee_deposit = TESTKUDOS:0.02
fee_refresh = TESTKUDOS:0.03
fee_refund = TESTKUDOS:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_kudos_2]
@ -139,6 +142,7 @@ fee_withdraw = TESTKUDOS:0.03
fee_deposit = TESTKUDOS:0.03
fee_refresh = TESTKUDOS:0.04
fee_refund = TESTKUDOS:0.02
CIPHER = RSA
rsa_keysize = 1024
[coin_kudos_4]
@ -150,6 +154,7 @@ fee_withdraw = TESTKUDOS:0.03
fee_deposit = TESTKUDOS:0.03
fee_refresh = TESTKUDOS:0.04
fee_refund = TESTKUDOS:0.02
CIPHER = RSA
rsa_keysize = 1024
[coin_kudos_5]
@ -161,6 +166,7 @@ fee_withdraw = TESTKUDOS:0.01
fee_deposit = TESTKUDOS:0.01
fee_refresh = TESTKUDOS:0.03
fee_refund = TESTKUDOS:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_kudos_8]
@ -172,6 +178,7 @@ fee_withdraw = TESTKUDOS:0.05
fee_deposit = TESTKUDOS:0.02
fee_refresh = TESTKUDOS:0.03
fee_refund = TESTKUDOS:0.04
CIPHER = RSA
rsa_keysize = 1024
[coin_kudos_10]
@ -183,6 +190,31 @@ fee_withdraw = TESTKUDOS:0.01
fee_deposit = TESTKUDOS:0.01
fee_refresh = TESTKUDOS:0.03
fee_refund = TESTKUDOS:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_kudos_ct_1]
value = TESTKUDOS:0.01
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = TESTKUDOS:0.01
fee_deposit = TESTKUDOS:0.01
fee_refresh = TESTKUDOS:0.01
fee_refund = TESTKUDOS:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_kudos_ct_10]
value = TESTKUDOS:0.10
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = TESTKUDOS:0.01
fee_deposit = TESTKUDOS:0.01
fee_refresh = TESTKUDOS:0.03
fee_refund = TESTKUDOS:0.01
CIPHER = RSA
rsa_keysize = 1024
[benchmark]

View File

@ -0,0 +1,128 @@
# This file is in the public domain.
#
[paths]
# Persistent data storage for the testcase
# This value is a default for `taler_config_home'
taler_test_home = exchange_benchmark_home/
[taler]
# Currency supported by the exchange (can only be one)
currency = EUR
CURRENCY_ROUND_UNIT = EUR:0.01
[exchange]
# how long is one signkey valid?
signkey_duration = 4 weeks
signkey_legal_duration = 2 years
# how long do we provide to clients denomination and signing keys
# ahead of time?
# Keep it short so the test runs fast.
lookahead_sign = 12h
# HTTP port the exchange listens to
port = 8081
# Master public key used to sign the exchange's various keys
master_public_key = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
# How to access our database
DB = postgres
# Base URL of the exchange. Must be set to a URL where the
# exchange (or the twister) is actually listening.
base_url = "http://localhost:8081/"
WIREWATCH_IDLE_SLEEP_INTERVAL = 1500 ms
[exchange-offline]
MASTER_PRIV_FILE = ${TALER_DATA_HOME}/exchange/offline-keys/master.priv
[auditor]
BASE_URL = "http://localhost:8083/"
[exchangedb-postgres]
config = "postgres:///talercheck"
[benchmark-remote-exchange]
host = localhost
# Adjust $HOME to match remote target!
dir = $HOME/repos/taler/exchange/src/benchmark
[bank]
HTTP_PORT = 8082
SERVE = http
MAX_DEBT = EUR:100000000000.0
MAX_DEBT_BANK = EUR:1000000000000000.0
[benchmark]
USER_PAYTO_URI = payto://x-taler-bank/localhost:8082/42
[exchange-account-2]
# What is the payto://-URL of the exchange (to generate wire response)
PAYTO_URI = "payto://x-taler-bank/localhost:8082/Exchange"
enable_debit = YES
enable_credit = YES
[exchange-accountcredentials-2]
# What is the bank account (with the "Taler Bank" demo system)? Must end with "/".
WIRE_GATEWAY_URL = http://localhost:8082/Exchange/
# Authentication information for basic authentication
WIRE_GATEWAY_AUTH_METHOD = "basic"
username = Exchange
password = x
# Sections starting with "coin_" specify which denominations
# the exchange should support (and their respective fee structure)
[coin_eur_ct_1]
value = EUR:0.01
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.00
fee_deposit = EUR:0.00
fee_refresh = EUR:0.01
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_ct_10]
value = EUR:0.10
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_1]
value = EUR:1
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_5]
value = EUR:5
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_10]
value = EUR:10
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS

View File

@ -81,6 +81,7 @@ fee_withdraw = EUR:0.00
fee_deposit = EUR:0.00
fee_refresh = EUR:0.01
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 2048
[coin_eur_ct_10]
@ -92,6 +93,7 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 2048
[coin_eur_1]
@ -103,6 +105,7 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 2048
[coin_eur_5]
@ -114,6 +117,7 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 2048
[coin_eur_10]
@ -125,4 +129,5 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 2048

View File

@ -0,0 +1,126 @@
# This file is in the public domain.
#
[paths]
# Persistent data storage for the testcase
# This value is a default for `taler_config_home'
TALER_TEST_HOME = exchange_benchmark_home/
[taler]
# Currency supported by the exchange (can only be one)
CURRENCY = EUR
CURRENCY_ROUND_UNIT = EUR:0.01
[exchange]
SIGNKEY_LEGAL_DURATION = 2 years
# HTTP port the exchange listens to
PORT = 8081
# Master public key used to sign the exchange's various keys
MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
# How to access our database
DB = postgres
# Base URL of the exchange. Must be set to a URL where the
# exchange (or the twister) is actually listening.
BASE_URL = "http://localhost:8081/"
AGGREGATOR_SHARD_SIZE = 67108864
#AGGREGATOR_SHARD_SIZE = 2147483648
WIREWATCH_IDLE_SLEEP_INTERVAL = 5 ms
[exchange-offline]
MASTER_PRIV_FILE = ${TALER_DATA_HOME}/exchange/offline-keys/master.priv
[auditor]
BASE_URL = "http://localhost:8083/"
[exchangedb-postgres]
CONFIG = "postgres:///talercheck"
[benchmark-remote-exchange]
HOST = localhost
# Adjust $HOME to match remote target!
DIR = $HOME/repos/taler/exchange/src/benchmark
[bank]
HTTP_PORT = 8082
SERVE = http
MAX_DEBT = EUR:100000000000.0
MAX_DEBT_BANK = EUR:1000000000000000.0
[benchmark]
USER_PAYTO_URI = payto://x-taler-bank/localhost:8082/42
[exchange-account-test]
# What is the bank account (with the "Taler Bank" demo system)? Must end with "/".
PAYTO_URI = "payto://x-taler-bank/localhost/Exchange"
# Authentication information for basic authentication
ENABLE_DEBIT = YES
ENABLE_CREDIT = YES
[exchange-accountcredentials-test]
WIRE_GATEWAY_URL = http://localhost:8082/Exchange/
WIRE_GATEWAY_AUTH_METHOD = "basic"
USERNAME = Exchange
PASSWORD = x
# Sections starting with "coin_" specify which denominations
# the exchange should support (and their respective fee structure)
[coin_eur_ct_1]
value = EUR:0.01
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.00
fee_deposit = EUR:0.00
fee_refresh = EUR:0.01
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_ct_10]
value = EUR:0.10
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_1]
value = EUR:1
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_5]
value = EUR:5
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_10]
value = EUR:10
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS

View File

@ -79,6 +79,7 @@ fee_withdraw = EUR:0.00
fee_deposit = EUR:0.00
fee_refresh = EUR:0.01
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 2048
[coin_eur_ct_10]
@ -90,6 +91,7 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 2048
[coin_eur_1]
@ -101,6 +103,7 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 2048
[coin_eur_5]
@ -112,6 +115,7 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 2048
[coin_eur_10]
@ -123,4 +127,5 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 2048

View File

@ -228,7 +228,7 @@ struct Merchant
/**
* Salt used when computing @e h_wire.
*/
struct TALER_WireSalt wire_salt;
struct TALER_WireSaltP wire_salt;
/**
* Account information for the merchant.
@ -490,8 +490,10 @@ run (void *cls,
struct TALER_CoinPubHash c_hash;
struct TALER_PlanchetDetail pd;
struct TALER_BlindedDenominationSignature bds;
union TALER_DenominationBlindingKeyP bks;
struct TALER_PlanchetSecretsP ps;
struct TALER_ExchangeWithdrawValues alg_values;
struct TALER_CoinSpendPublicKeyP coin_pub;
union TALER_DenominationBlindingKeyP bks;
RANDOMIZE (&coin_pub);
GNUNET_assert (GNUNET_OK ==
@ -499,6 +501,7 @@ run (void *cls,
&denom_pub,
TALER_DENOMINATION_RSA,
1024));
alg_values.cipher = TALER_DENOMINATION_RSA;
TALER_denom_pub_hash (&denom_pub,
&h_denom_pub);
make_amountN (2, 0, &issue.properties.value);
@ -518,21 +521,23 @@ run (void *cls,
return;
}
TALER_blinding_secret_create (&bks);
TALER_planchet_blinding_secret_create (&ps,
&alg_values,
&bks);
GNUNET_assert (GNUNET_OK ==
TALER_denom_blind (&denom_pub,
&bks,
NULL, /* FIXME-oec */
&coin_pub,
&alg_values,
&c_hash,
&pd.coin_ev,
&pd.coin_ev_size));
&pd.blinded_planchet));
GNUNET_assert (GNUNET_OK ==
TALER_denom_sign_blinded (&bds,
&pk,
pd.coin_ev,
pd.coin_ev_size));
GNUNET_free (pd.coin_ev);
&pd.blinded_planchet));
TALER_blinded_planchet_free (&pd.blinded_planchet);
GNUNET_assert (GNUNET_OK ==
TALER_denom_sig_unblind (&denom_sig,
&bds,

View File

@ -178,6 +178,7 @@ run (void *cls,
"sent response\n");
continue;
}
#if FIXME_FLORIAN
if (0 == strcmp ("setup_refresh_planchet", op))
{
struct TALER_TransferSecretP transfer_secret;
@ -204,7 +205,7 @@ run (void *cls,
global_ret = 1;
return;
}
TALER_planchet_setup_refresh (&transfer_secret,
TALER_transfer_secret_to_planchet_secret (&transfer_secret,
coin_index,
&ps);
GNUNET_CRYPTO_eddsa_key_get_public (&ps.coin_priv.eddsa_priv,
@ -222,6 +223,7 @@ run (void *cls,
"sent response\n");
continue;
}
#endif
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"unsupported operation '%s'\n",
op);

View File

@ -2531,10 +2531,10 @@ do_download (char *const *args)
* #GNUNET_SYSERR if keys changed from what we remember or other error
*/
static int
tofu_check (const struct TALER_SecurityModulePublicKeyP secm[2])
tofu_check (const struct TALER_SecurityModulePublicKeySetP *secmset)
{
char *fn;
struct TALER_SecurityModulePublicKeyP old[2];
struct TALER_SecurityModulePublicKeySetP oldset;
ssize_t ret;
if (GNUNET_OK !=
@ -2552,11 +2552,11 @@ tofu_check (const struct TALER_SecurityModulePublicKeyP secm[2])
GNUNET_DISK_file_test (fn))
{
ret = GNUNET_DISK_fn_read (fn,
&old,
sizeof (old));
&oldset,
sizeof (oldset));
if (GNUNET_SYSERR != ret)
{
if (ret != sizeof (old))
if (ret != sizeof (oldset))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"File `%s' corrupt\n",
@ -2565,9 +2565,9 @@ tofu_check (const struct TALER_SecurityModulePublicKeyP secm[2])
return GNUNET_SYSERR;
}
/* TOFU check */
if (0 != memcmp (old,
secm,
sizeof (old)))
if (0 != memcmp (&oldset,
secmset,
sizeof (*secmset)))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Fatal: security module keys changed (file `%s')!\n",
@ -2608,7 +2608,7 @@ tofu_check (const struct TALER_SecurityModulePublicKeyP secm[2])
GNUNET_free (key);
if (0 !=
GNUNET_memcmp (&k,
&secm[1]))
&secmset->eddsa))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"ESIGN security module key does not match SECM_ESIGN_PUBKEY in configuration\n");
@ -2639,13 +2639,44 @@ tofu_check (const struct TALER_SecurityModulePublicKeyP secm[2])
GNUNET_free (key);
if (0 !=
GNUNET_memcmp (&k,
&secm[0]))
&secmset->rsa))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"DENOM security module key does not match SECM_DENOM_PUBKEY in configuration\n");
return GNUNET_SYSERR;
}
}
if (GNUNET_OK ==
GNUNET_CONFIGURATION_get_value_string (kcfg,
"exchange-offline",
"SECM_DENOM_CS_PUBKEY",
&key))
{
struct TALER_SecurityModulePublicKeyP k;
if (GNUNET_OK !=
GNUNET_STRINGS_string_to_data (key,
strlen (key),
&k,
sizeof (k)))
{
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
"exchange-offline",
"SECM_DENOM_CS_PUBKEY",
"key malformed");
GNUNET_free (key);
return GNUNET_SYSERR;
}
GNUNET_free (key);
if (0 !=
GNUNET_memcmp (&k,
&secmset->cs))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"DENOM security module key does not match SECM_DENOM_CS_PUBKEY in configuration\n");
return GNUNET_SYSERR;
}
}
}
if (GNUNET_OK !=
GNUNET_DISK_directory_create_for_file (fn))
@ -2659,8 +2690,8 @@ tofu_check (const struct TALER_SecurityModulePublicKeyP secm[2])
/* persist keys for future runs */
if (GNUNET_OK !=
GNUNET_DISK_fn_write (fn,
secm,
sizeof (old),
secmset,
sizeof (oldset),
GNUNET_DISK_PERM_USER_READ))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@ -2766,11 +2797,14 @@ show_signkeys (const struct TALER_SecurityModulePublicKeyP *secm_pub,
* Output @a denomkeys for human consumption.
*
* @param secm_pub security module public key used to sign the denominations
* element 0: RSA
* element 1: CS
* @param denomkeys keys to output
* @return #GNUNET_OK on success
*/
static int
show_denomkeys (const struct TALER_SecurityModulePublicKeyP *secm_pub,
show_denomkeys (const struct TALER_SecurityModulePublicKeyP *secm_pub_rsa,
const struct TALER_SecurityModulePublicKeyP *secm_pub_cs,
const json_t *denomkeys)
{
size_t index;
@ -2863,7 +2897,21 @@ show_denomkeys (const struct TALER_SecurityModulePublicKeyP *secm_pub,
section_name,
stamp_start,
duration,
secm_pub,
secm_pub_rsa,
&secm_sig);
}
break;
case TALER_DENOMINATION_CS:
{
struct TALER_CsPubHashP h_cs;
TALER_cs_pub_hash (&denom_pub.details.cs_public_key,
&h_cs);
ok = TALER_exchange_secmod_cs_verify (&h_cs,
section_name,
stamp_start,
duration,
secm_pub_cs,
&secm_sig);
}
break;
@ -3018,7 +3066,7 @@ do_show (char *const *args)
json_t *denomkeys;
json_t *signkeys;
struct TALER_MasterPublicKeyP mpub;
struct TALER_SecurityModulePublicKeyP secm[2];
struct TALER_SecurityModulePublicKeySetP secmset;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_json ("future_denoms",
&denomkeys),
@ -3027,9 +3075,11 @@ do_show (char *const *args)
GNUNET_JSON_spec_fixed_auto ("master_pub",
&mpub),
GNUNET_JSON_spec_fixed_auto ("denom_secmod_public_key",
&secm[0]),
&secmset.rsa),
GNUNET_JSON_spec_fixed_auto ("denom_secmod_cs_public_key",
&secmset.cs),
GNUNET_JSON_spec_fixed_auto ("signkey_secmod_public_key",
&secm[1]),
&secmset.eddsa),
GNUNET_JSON_spec_end ()
};
@ -3070,7 +3120,7 @@ do_show (char *const *args)
return;
}
if (GNUNET_SYSERR ==
tofu_check (secm))
tofu_check (&secmset))
{
global_ret = EXIT_FAILURE;
test_shutdown ();
@ -3079,10 +3129,11 @@ do_show (char *const *args)
return;
}
if ( (GNUNET_OK !=
show_signkeys (&secm[1],
show_signkeys (&secmset.eddsa,
signkeys)) ||
(GNUNET_OK !=
show_denomkeys (&secm[0],
show_denomkeys (&secmset.rsa,
&secmset.cs,
denomkeys)) )
{
global_ret = EXIT_FAILURE;
@ -3200,12 +3251,15 @@ sign_signkeys (const struct TALER_SecurityModulePublicKeyP *secm_pub,
* Sign @a denomkeys with offline key.
*
* @param secm_pub security module public key used to sign the denominations
* element 0: RSA
* element 1: CS
* @param denomkeys keys to output
* @param[in,out] result array where to output the signatures
* @return #GNUNET_OK on success
*/
static enum GNUNET_GenericReturnValue
sign_denomkeys (const struct TALER_SecurityModulePublicKeyP *secm_pub,
sign_denomkeys (const struct TALER_SecurityModulePublicKeyP *secm_pub_rsa,
const struct TALER_SecurityModulePublicKeyP *secm_pub_cs,
const json_t *denomkeys,
json_t *result)
{
@ -3300,7 +3354,31 @@ sign_denomkeys (const struct TALER_SecurityModulePublicKeyP *secm_pub,
section_name,
stamp_start,
duration,
secm_pub,
secm_pub_rsa,
&secm_sig))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Invalid security module signature for denomination key %s (aborting)\n",
GNUNET_h2s (&h_denom_pub.hash));
global_ret = EXIT_FAILURE;
test_shutdown ();
GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
}
break;
case TALER_DENOMINATION_CS:
{
struct TALER_CsPubHashP h_cs;
TALER_cs_pub_hash (&denom_pub.details.cs_public_key,
&h_cs);
if (GNUNET_OK !=
TALER_exchange_secmod_cs_verify (&h_cs,
section_name,
stamp_start,
duration,
secm_pub_cs,
&secm_sig))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
@ -3364,7 +3442,7 @@ do_sign (char *const *args)
json_t *denomkeys;
json_t *signkeys;
struct TALER_MasterPublicKeyP mpub;
struct TALER_SecurityModulePublicKeyP secm[2];
struct TALER_SecurityModulePublicKeySetP secmset;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_json ("future_denoms",
&denomkeys),
@ -3373,9 +3451,11 @@ do_sign (char *const *args)
GNUNET_JSON_spec_fixed_auto ("master_pub",
&mpub),
GNUNET_JSON_spec_fixed_auto ("denom_secmod_public_key",
&secm[0]),
&secmset.rsa),
GNUNET_JSON_spec_fixed_auto ("denom_secmod_cs_public_key",
&secmset.cs),
GNUNET_JSON_spec_fixed_auto ("signkey_secmod_public_key",
&secm[1]),
&secmset.eddsa),
GNUNET_JSON_spec_end ()
};
@ -3419,7 +3499,7 @@ do_sign (char *const *args)
return;
}
if (GNUNET_SYSERR ==
tofu_check (secm))
tofu_check (&secmset))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Fatal: security module keys changed!\n");
@ -3436,11 +3516,12 @@ do_sign (char *const *args)
GNUNET_assert (NULL != signkey_sig_array);
GNUNET_assert (NULL != denomkey_sig_array);
if ( (GNUNET_OK !=
sign_signkeys (&secm[1],
sign_signkeys (&secmset.eddsa,
signkeys,
signkey_sig_array)) ||
(GNUNET_OK !=
sign_denomkeys (&secm[0],
sign_denomkeys (&secmset.rsa,
&secmset.cs,
denomkeys,
denomkey_sig_array)) )
{

View File

@ -79,6 +79,7 @@ taler_exchange_transfer_LDADD = \
taler_exchange_httpd_SOURCES = \
taler-exchange-httpd.c taler-exchange-httpd.h \
taler-exchange-httpd_auditors.c taler-exchange-httpd_auditors.h \
taler-exchange-httpd_csr.c taler-exchange-httpd_csr \
taler-exchange-httpd_db.c taler-exchange-httpd_db.h \
taler-exchange-httpd_deposit.c taler-exchange-httpd_deposit.h \
taler-exchange-httpd_deposits_get.c taler-exchange-httpd_deposits_get.h \

View File

@ -30,6 +30,7 @@
#include <limits.h>
#include "taler_mhd_lib.h"
#include "taler-exchange-httpd_auditors.h"
#include "taler-exchange-httpd_csr.h"
#include "taler-exchange-httpd_deposit.h"
#include "taler-exchange-httpd_deposits_get.h"
#include "taler-exchange-httpd_extensions.h"
@ -910,6 +911,13 @@ handle_mhd_request (void *cls,
.method = MHD_HTTP_METHOD_GET,
.handler.get = &TEH_handler_wire
},
/* request R, used in clause schnorr withdraw and refresh */
{
.url = "csr",
.method = MHD_HTTP_METHOD_POST,
.handler.post = &TEH_handler_csr,
.nargs = 0
},
/* Withdrawing coins / interaction with reserves */
{
.url = "reserves",

View File

@ -0,0 +1,206 @@
/*
This file is part of TALER
Copyright (C) 2014-2021 Taler Systems SA
TALER is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation; either version 3,
or (at your option) any later version.
TALER is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General
Public License along with TALER; see the file COPYING. If not,
see <http://www.gnu.org/licenses/>
*/
/**
* @file taler-exchange-httpd_csr.c
* @brief Handle /csr requests
* @author Lucien Heuzeveldt
* @author Gian Demarmles
*/
#include "platform.h"
#include <gnunet/gnunet_util_lib.h>
#include <jansson.h>
#include "taler_json_lib.h"
#include "taler_mhd_lib.h"
#include "taler-exchange-httpd_csr.h"
#include "taler-exchange-httpd_responses.h"
#include "taler-exchange-httpd_keys.h"
MHD_RESULT
TEH_handler_csr (struct TEH_RequestContext *rc,
const json_t *root,
const char *const args[])
{
unsigned int csr_requests_num;
json_t *csr_requests;
json_t *csr_response;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_json ("nks",
&csr_requests),
GNUNET_JSON_spec_end ()
};
enum TALER_ErrorCode ec;
struct TEH_DenominationKey *dk;
(void) args;
// parse input
{
enum GNUNET_GenericReturnValue res;
res = TALER_MHD_parse_json_data (rc->connection,
root,
spec);
GNUNET_JSON_parse_free (spec);
if (GNUNET_OK != res)
return (GNUNET_SYSERR == res) ? MHD_NO : MHD_YES;
}
csr_requests_num = json_array_size (csr_requests);
if (TALER_MAX_FRESH_COINS <= csr_requests_num)
{
return TALER_MHD_reply_with_error (
rc->connection,
MHD_HTTP_BAD_REQUEST,
// FIXME: generalize error message
TALER_EC_EXCHANGE_REFRESHES_REVEAL_NEW_DENOMS_ARRAY_SIZE_EXCESSIVE,
NULL);
}
struct TALER_CsNonce nonces[GNUNET_NZL (csr_requests_num)];
struct TALER_DenominationHash denom_pub_hashes[GNUNET_NZL (csr_requests_num)];
for (unsigned int i = 0; i < csr_requests_num; i++)
{
struct TALER_CsNonce *nonce = &nonces[i];
struct TALER_DenominationHash *denom_pub_hash = &denom_pub_hashes[i];
struct GNUNET_JSON_Specification csr_spec[] = {
GNUNET_JSON_spec_fixed ("nonce",
nonce,
sizeof (struct TALER_CsNonce)),
GNUNET_JSON_spec_fixed ("denom_pub_hash",
denom_pub_hash,
sizeof (struct TALER_DenominationHash)),
GNUNET_JSON_spec_end ()
};
enum GNUNET_GenericReturnValue res;
res = TALER_MHD_parse_json_array (rc->connection,
root,
csr_spec,
i,
-1);
if (GNUNET_OK != res)
return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
}
struct TALER_DenominationCSPublicRPairP r_pubs[GNUNET_NZL (csr_requests_num)];
for (unsigned int i = 0; i < csr_requests_num; i++)
{
const struct TALER_CsNonce *nonce = &nonces[i];
const struct TALER_DenominationHash *denom_pub_hash = &denom_pub_hashes[i];
struct TALER_DenominationCSPublicRPairP *r_pub = &r_pubs[i];
// check denomination referenced by denom_pub_hash
{
struct TEH_KeyStateHandle *ksh;
ksh = TEH_keys_get_state ();
if (NULL == ksh)
{
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING,
NULL);
}
dk = TEH_keys_denomination_by_hash2 (ksh,
denom_pub_hash,
NULL,
NULL);
if (NULL == dk)
{
return TEH_RESPONSE_reply_unknown_denom_pub_hash (
rc->connection,
&denom_pub_hash[i]);
}
if (GNUNET_TIME_absolute_is_past (dk->meta.expire_withdraw.abs_time))
{
/* This denomination is past the expiration time for withdraws/refreshes*/
return TEH_RESPONSE_reply_expired_denom_pub_hash (
rc->connection,
denom_pub_hash,
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_EXPIRED,
"CSR");
}
if (GNUNET_TIME_absolute_is_future (dk->meta.start.abs_time))
{
/* This denomination is not yet valid, no need to check
for idempotency! */
return TEH_RESPONSE_reply_expired_denom_pub_hash (
rc->connection,
denom_pub_hash,
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_VALIDITY_IN_FUTURE,
"CSR");
}
if (dk->recoup_possible)
{
/* This denomination has been revoked */
return TEH_RESPONSE_reply_expired_denom_pub_hash (
rc->connection,
denom_pub_hash,
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED,
"CSR");
}
if (TALER_DENOMINATION_CS != dk->denom_pub.cipher)
{
// denomination is valid but not CS
return TEH_RESPONSE_reply_invalid_denom_cipher_for_operation (
rc->connection,
denom_pub_hash);
}
}
// derive r_pub
// FIXME: bundle all requests into one derivation request (TEH_keys_..., crypto helper, security module)
ec = TEH_keys_denomination_cs_r_pub (denom_pub_hash,
nonce,
r_pub);
if (TALER_EC_NONE != ec)
{
GNUNET_break (0);
return TALER_MHD_reply_with_ec (rc->connection,
ec,
NULL);
}
}
// send response
csr_response = json_array ();
for (unsigned int i = 0; i < csr_requests_num; i++)
{
const struct TALER_DenominationCSPublicRPairP *r_pub = &r_pubs[i];
json_t *csr_obj;
csr_obj = GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_varsize ("r_pub_0",
&r_pub->r_pub[0],
sizeof(struct GNUNET_CRYPTO_CsRPublic)),
GNUNET_JSON_pack_data_varsize ("r_pub_1",
&r_pub->r_pub[1],
sizeof(struct GNUNET_CRYPTO_CsRPublic)));
GNUNET_assert (NULL != csr_obj);
GNUNET_assert (0 ==
json_array_append_new (csr_response,
csr_obj));
}
return TALER_MHD_reply_json (rc->connection,
csr_response,
MHD_HTTP_OK);
}
/* end of taler-exchange-httpd_csr.c */

View File

@ -0,0 +1,43 @@
/*
This file is part of TALER
Copyright (C) 2014-2021 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file taler-exchange-httpd_csr.h
* @brief Handle /csr requests
* @author Lucien Heuzeveldt
* @author Gian Demarmles
*/
#ifndef TALER_EXCHANGE_HTTPD_CSR_H
#define TALER_EXCHANGE_HTTPD_CSR_H
#include <microhttpd.h>
#include "taler-exchange-httpd.h"
/**
* Handle a "/csr" request. Parses the "nonce" and
* the "denom_pub_hash" (identifying a denomination) used to derive the r_pub.
*
* @param rc request context
* @param root uploaded JSON data
* @param args empty array
* @return MHD result code
*/
MHD_RESULT
TEH_handler_csr (struct TEH_RequestContext *rc,
const json_t *root,
const char *const args[]);
#endif

View File

@ -356,6 +356,15 @@ TEH_handler_deposit (struct MHD_Connection *connection,
TALER_EC_EXCHANGE_GENERIC_DENOMINATION_REVOKED,
"DEPOSIT");
}
if (dk->denom_pub.cipher != deposit.coin.denom_sig.cipher)
{
/* denomination cipher and denomination signature cipher not the same */
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_GENERIC_CIPHER_MISMATCH,
NULL);
}
deposit.deposit_fee = dk->meta.fee_deposit;
/* check coin signature */

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2020, 2021 Taler Systems SA
Copyright (C) 2020-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
@ -103,6 +103,11 @@ struct HelperDenomination
*/
struct TALER_RsaPubHashP h_rsa;
/**
* Hash of the CS key.
*/
struct TALER_CsPubHashP h_cs;
} h_details;
/**
@ -188,7 +193,12 @@ struct HelperState
/**
* Handle for the denom/RSA helper.
*/
struct TALER_CRYPTO_RsaDenominationHelper *dh;
struct TALER_CRYPTO_RsaDenominationHelper *rsadh;
/**
* Handle for the denom/CS helper.
*/
struct TALER_CRYPTO_CsDenominationHelper *csdh;
/**
* Map from H(denom_pub) to `struct HelperDenomination` entries.
@ -200,6 +210,11 @@ struct HelperState
*/
struct GNUNET_CONTAINER_MultiHashMap *rsa_keys;
/**
* Map from H(cs_pub) to `struct HelperDenomination` entries.
*/
struct GNUNET_CONTAINER_MultiHashMap *cs_keys;
/**
* Map from `struct TALER_ExchangePublicKey` to `struct HelperSignkey`
* entries. Based on the fact that a `struct GNUNET_PeerIdentity` is also
@ -424,7 +439,12 @@ static struct GNUNET_TIME_Relative signkey_legal_duration;
/**
* RSA security module public key, all zero if not known.
*/
static struct TALER_SecurityModulePublicKeyP denom_sm_pub;
static struct TALER_SecurityModulePublicKeyP denom_rsa_sm_pub;
/**
* CS security module public key, all zero if not known.
*/
static struct TALER_SecurityModulePublicKeyP denom_cs_sm_pub;
/**
* EdDSA security module public key, all zero if not known.
@ -541,6 +561,7 @@ check_dk (void *cls,
if (TALER_DENOMINATION_RSA == dk->denom_pub.cipher)
GNUNET_assert (GNUNET_CRYPTO_rsa_public_key_check (
dk->denom_pub.details.rsa_public_key));
// nothing to do for TALER_DENOMINATION_CS
return GNUNET_OK;
}
@ -609,19 +630,43 @@ clear_response_cache (struct TEH_KeyStateHandle *ksh)
* @param sm_pub RSA security module public key to check
*/
static void
check_denom_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub)
check_denom_rsa_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub)
{
if (0 !=
GNUNET_memcmp (sm_pub,
&denom_sm_pub))
&denom_rsa_sm_pub))
{
if (! GNUNET_is_zero (&denom_sm_pub))
if (! GNUNET_is_zero (&denom_rsa_sm_pub))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Our RSA security module changed its key. This must not happen.\n");
GNUNET_assert (0);
}
denom_sm_pub = *sm_pub; /* TOFU ;-) */
denom_rsa_sm_pub = *sm_pub; /* TOFU ;-) */
}
}
/**
* Check that the given CS security module's public key is the one
* we have pinned. If it does not match, we die hard.
*
* @param sm_pub RSA security module public key to check
*/
static void
check_denom_cs_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub)
{
if (0 !=
GNUNET_memcmp (sm_pub,
&denom_cs_sm_pub))
{
if (! GNUNET_is_zero (&denom_cs_sm_pub))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Our CS security module changed its key. This must not happen.\n");
GNUNET_assert (0);
}
denom_cs_sm_pub = *sm_pub; /* TOFU ;-) */
}
}
@ -659,7 +704,7 @@ check_esign_sm_pub (const struct TALER_SecurityModulePublicKeyP *sm_pub)
* @param value the `struct HelperDenomination` to release
* @return #GNUNET_OK (continue to iterate)
*/
static int
static enum GNUNET_GenericReturnValue
free_denom_cb (void *cls,
const struct GNUNET_HashCode *h_denom_pub,
void *value)
@ -712,6 +757,8 @@ destroy_key_helpers (struct HelperState *hs)
hs);
GNUNET_CONTAINER_multihashmap_destroy (hs->rsa_keys);
hs->rsa_keys = NULL;
GNUNET_CONTAINER_multihashmap_destroy (hs->cs_keys);
hs->cs_keys = NULL;
GNUNET_CONTAINER_multihashmap_destroy (hs->denom_keys);
hs->denom_keys = NULL;
GNUNET_CONTAINER_multipeermap_iterate (hs->esign_keys,
@ -719,10 +766,15 @@ destroy_key_helpers (struct HelperState *hs)
hs);
GNUNET_CONTAINER_multipeermap_destroy (hs->esign_keys);
hs->esign_keys = NULL;
if (NULL != hs->dh)
if (NULL != hs->rsadh)
{
TALER_CRYPTO_helper_rsa_disconnect (hs->dh);
hs->dh = NULL;
TALER_CRYPTO_helper_rsa_disconnect (hs->rsadh);
hs->rsadh = NULL;
}
if (NULL != hs->csdh)
{
TALER_CRYPTO_helper_cs_disconnect (hs->csdh);
hs->csdh = NULL;
}
if (NULL != hs->esh)
{
@ -752,8 +804,7 @@ load_age_mask (const char*section_name)
/* TODO: optimize by putting this into global? */
if (TALER_extensions_is_enabled (age_ext))
age_mask = *(struct TALER_AgeMask *) age_ext->config;
if (age_mask.mask == 0)
if (0 == age_mask.mask)
{
/* Age restriction support is not enabled. Ignore the AGE_RESTRICTED field
* for the particular denomination and simply return the null_mask
@ -767,7 +818,9 @@ load_age_mask (const char*section_name)
"AGE_RESTRICTED")))
{
enum GNUNET_GenericReturnValue ret;
if (GNUNET_SYSERR == (ret = GNUNET_CONFIGURATION_get_value_yesno (TEH_cfg,
if (GNUNET_SYSERR ==
(ret = GNUNET_CONFIGURATION_get_value_yesno (TEH_cfg,
section_name,
"AGE_RESTRICTED")))
{
@ -778,7 +831,6 @@ load_age_mask (const char*section_name)
return null_mask;
}
}
return age_mask;
}
@ -795,7 +847,7 @@ load_age_mask (const char*section_name)
* zero if the key has been revoked or purged
* @param validity_duration how long does the key remain available for signing;
* zero if the key has been revoked or purged
* @param h_denom_pub hash of the @a denom_pub that is available (or was purged)
* @param h_rsa hash of the @a denom_pub that is available (or was purged)
* @param denom_pub the public key itself, NULL if the key was revoked or purged
* @param sm_pub public key of the security module, NULL if the key was revoked or purged
* @param sm_sig signature from the security module, NULL if the key was revoked or purged
@ -822,6 +874,7 @@ helper_rsa_cb (
GNUNET_STRINGS_relative_time_to_string (validity_duration,
GNUNET_NO));
key_generation++;
// FIXME: wait for sync?
TEH_resume_keys_requests (false);
hd = GNUNET_CONTAINER_multihashmap_get (hs->rsa_keys,
&h_rsa->hash);
@ -832,7 +885,7 @@ helper_rsa_cb (
return;
}
GNUNET_assert (NULL != sm_pub);
check_denom_sm_pub (sm_pub);
check_denom_rsa_sm_pub (sm_pub);
hd = GNUNET_new (struct HelperDenomination);
hd->start_time = start_time;
hd->validity_duration = validity_duration;
@ -864,6 +917,87 @@ helper_rsa_cb (
}
/**
* Function called with information about available CS keys for signing. Usually
* only called once per key upon connect. Also called again in case a key is
* being revoked, in that case with an @a end_time of zero.
*
* @param cls closure with the `struct HelperState *`
* @param section_name name of the denomination type in the configuration;
* NULL if the key has been revoked or purged
* @param start_time when does the key become available for signing;
* zero if the key has been revoked or purged
* @param validity_duration how long does the key remain available for signing;
* zero if the key has been revoked or purged
* @param h_cs hash of the @a denom_pub that is available (or was purged)
* @param denom_pub the public key itself, NULL if the key was revoked or purged
* @param sm_pub public key of the security module, NULL if the key was revoked or purged
* @param sm_sig signature from the security module, NULL if the key was revoked or purged
* The signature was already verified against @a sm_pub.
*/
static void
helper_cs_cb (
void *cls,
const char *section_name,
struct GNUNET_TIME_Timestamp start_time,
struct GNUNET_TIME_Relative validity_duration,
const struct TALER_CsPubHashP *h_cs,
const struct TALER_DenominationPublicKey *denom_pub,
const struct TALER_SecurityModulePublicKeyP *sm_pub,
const struct TALER_SecurityModuleSignatureP *sm_sig)
{
struct HelperState *hs = cls;
struct HelperDenomination *hd;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"CS helper announces key %s for denomination type %s with validity %s\n",
GNUNET_h2s (&h_cs->hash),
section_name,
GNUNET_STRINGS_relative_time_to_string (validity_duration,
GNUNET_NO));
key_generation++;
// FIXME: wait for sync?
TEH_resume_keys_requests (false);
hd = GNUNET_CONTAINER_multihashmap_get (hs->cs_keys,
&h_cs->hash);
if (NULL != hd)
{
/* should be just an update (revocation!), so update existing entry */
hd->validity_duration = validity_duration;
return;
}
GNUNET_assert (NULL != sm_pub);
check_denom_cs_sm_pub (sm_pub);
hd = GNUNET_new (struct HelperDenomination);
hd->start_time = start_time;
hd->validity_duration = validity_duration;
hd->h_details.h_cs = *h_cs;
hd->sm_sig = *sm_sig;
GNUNET_assert (TALER_DENOMINATION_CS == denom_pub->cipher);
TALER_denom_pub_deep_copy (&hd->denom_pub,
denom_pub);
/* load the age mask for the denomination, if applicable */
hd->denom_pub.age_mask = load_age_mask (section_name);
TALER_denom_pub_hash (&hd->denom_pub,
&hd->h_denom_pub);
hd->section_name = GNUNET_strdup (section_name);
GNUNET_assert (
GNUNET_OK ==
GNUNET_CONTAINER_multihashmap_put (
hs->denom_keys,
&hd->h_denom_pub.hash,
hd,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
GNUNET_assert (
GNUNET_OK ==
GNUNET_CONTAINER_multihashmap_put (
hs->cs_keys,
&hd->h_details.h_cs.hash,
hd,
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
}
/**
* Function called with information about available keys for signing. Usually
* only called once per key upon connect. Also called again in case a key is
@ -940,13 +1074,24 @@ setup_key_helpers (struct HelperState *hs)
hs->rsa_keys
= GNUNET_CONTAINER_multihashmap_create (1024,
GNUNET_YES);
hs->cs_keys
= GNUNET_CONTAINER_multihashmap_create (1024,
GNUNET_YES);
hs->esign_keys
= GNUNET_CONTAINER_multipeermap_create (32,
GNUNET_NO /* MUST BE NO! */);
hs->dh = TALER_CRYPTO_helper_rsa_connect (TEH_cfg,
hs->rsadh = TALER_CRYPTO_helper_rsa_connect (TEH_cfg,
&helper_rsa_cb,
hs);
if (NULL == hs->dh)
if (NULL == hs->rsadh)
{
destroy_key_helpers (hs);
return GNUNET_SYSERR;
}
hs->csdh = TALER_CRYPTO_helper_cs_connect (TEH_cfg,
&helper_cs_cb,
hs);
if (NULL == hs->csdh)
{
destroy_key_helpers (hs);
return GNUNET_SYSERR;
@ -971,7 +1116,8 @@ setup_key_helpers (struct HelperState *hs)
static void
sync_key_helpers (struct HelperState *hs)
{
TALER_CRYPTO_helper_rsa_poll (hs->dh);
TALER_CRYPTO_helper_rsa_poll (hs->rsadh);
TALER_CRYPTO_helper_cs_poll (hs->csdh);
TALER_CRYPTO_helper_esign_poll (hs->esh);
}
@ -984,7 +1130,7 @@ sync_key_helpers (struct HelperState *hs)
* @param value a `struct TEH_DenominationKey` to free
* @return #GNUNET_OK (continue to iterate)
*/
static int
static enum GNUNET_GenericReturnValue
clear_denomination_cb (void *cls,
const struct GNUNET_HashCode *h_denom_pub,
void *value)
@ -1015,7 +1161,7 @@ clear_denomination_cb (void *cls,
* @param value a `struct SigningKey` to free
* @return #GNUNET_OK (continue to iterate)
*/
static int
static enum GNUNET_GenericReturnValue
clear_signkey_cb (void *cls,
const struct GNUNET_PeerIdentity *pid,
void *value)
@ -1255,7 +1401,7 @@ struct GetAuditorSigsContext
* @param value a `struct TEH_DenominationKey`
* @return #GNUNET_OK (continue to iterate)
*/
static int
static enum GNUNET_GenericReturnValue
get_auditor_sigs (void *cls,
const struct GNUNET_HashCode *h_denom_pub,
void *value)
@ -1388,7 +1534,7 @@ struct SignKeyCtx
* @param value a `struct SigningKey`
* @return #GNUNET_OK (continue to iterate)
*/
static int
static enum GNUNET_GenericReturnValue
add_sign_key_cb (void *cls,
const struct GNUNET_PeerIdentity *pid,
void *value)
@ -1457,7 +1603,7 @@ struct DenomKeyCtx
* @param value a `struct TEH_DenominationKey`
* @return #GNUNET_OK (continue to iterate)
*/
static int
static enum GNUNET_GenericReturnValue
add_denom_key_cb (void *cls,
const struct GNUNET_HashCode *h_denom_pub,
void *value)
@ -2265,8 +2411,7 @@ TEH_keys_denomination_by_hash2 (
struct TALER_BlindedDenominationSignature
TEH_keys_denomination_sign (const struct TALER_DenominationHash *h_denom_pub,
const void *msg,
size_t msg_size,
const struct TEH_SignDetails *msg,
enum TALER_ErrorCode *ec)
{
struct TEH_KeyStateHandle *ksh;
@ -2289,13 +2434,23 @@ TEH_keys_denomination_sign (const struct TALER_DenominationHash *h_denom_pub,
*ec = TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
return none;
}
if (msg->cipher != hd->denom_pub.cipher)
{
*ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
return none;
}
switch (hd->denom_pub.cipher)
{
case TALER_DENOMINATION_RSA:
return TALER_CRYPTO_helper_rsa_sign (ksh->helpers->dh,
return TALER_CRYPTO_helper_rsa_sign (ksh->helpers->rsadh,
&hd->h_details.h_rsa,
msg,
msg_size,
msg->details.rsa_message.msg,
msg->details.rsa_message.msg_size,
ec);
case TALER_DENOMINATION_CS:
return TALER_CRYPTO_helper_cs_sign (ksh->helpers->csdh,
&hd->h_details.h_cs,
&msg->details.cs_message,
ec);
default:
*ec = TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
@ -2304,6 +2459,40 @@ TEH_keys_denomination_sign (const struct TALER_DenominationHash *h_denom_pub,
}
enum TALER_ErrorCode
TEH_keys_denomination_cs_r_pub (const struct
TALER_DenominationHash *h_denom_pub,
const struct TALER_CsNonce *nonce,
struct TALER_DenominationCSPublicRPairP *r_pub)
{
struct TEH_KeyStateHandle *ksh;
struct HelperDenomination *hd;
enum TALER_ErrorCode r_derive_ec;
ksh = TEH_keys_get_state ();
if (NULL == ksh)
{
return TALER_EC_EXCHANGE_GENERIC_KEYS_MISSING;
}
hd = GNUNET_CONTAINER_multihashmap_get (ksh->helpers->denom_keys,
&h_denom_pub->hash);
if (NULL == hd)
{
return TALER_EC_EXCHANGE_GENERIC_DENOMINATION_KEY_UNKNOWN;
}
if (TALER_DENOMINATION_CS != hd->denom_pub.cipher)
{
return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
}
*r_pub = TALER_CRYPTO_helper_cs_r_derive (ksh->helpers->csdh,
&hd->h_details.h_cs,
nonce,
&r_derive_ec);
return r_derive_ec;
}
void
TEH_keys_denomination_revoke (const struct TALER_DenominationHash *h_denom_pub)
{
@ -2326,10 +2515,15 @@ TEH_keys_denomination_revoke (const struct TALER_DenominationHash *h_denom_pub)
switch (hd->denom_pub.cipher)
{
case TALER_DENOMINATION_RSA:
TALER_CRYPTO_helper_rsa_revoke (ksh->helpers->dh,
TALER_CRYPTO_helper_rsa_revoke (ksh->helpers->rsadh,
&hd->h_details.h_rsa);
TEH_keys_update_states ();
return;
case TALER_DENOMINATION_CS:
TALER_CRYPTO_helper_cs_revoke (ksh->helpers->csdh,
&hd->h_details.h_cs);
TEH_keys_update_states ();
return;
default:
GNUNET_break (0);
return;
@ -2923,7 +3117,8 @@ TEH_keys_management_get_keys_handler (const struct TEH_RequestHandler *rh,
.signkeys = json_array ()
};
if (GNUNET_is_zero (&denom_sm_pub))
if ( (GNUNET_is_zero (&denom_rsa_sm_pub)) &&
(GNUNET_is_zero (&denom_cs_sm_pub)) )
{
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_BAD_GATEWAY,
@ -2954,7 +3149,9 @@ TEH_keys_management_get_keys_handler (const struct TEH_RequestHandler *rh,
GNUNET_JSON_pack_data_auto ("master_pub",
&TEH_master_public_key),
GNUNET_JSON_pack_data_auto ("denom_secmod_public_key",
&denom_sm_pub),
&denom_rsa_sm_pub),
GNUNET_JSON_pack_data_auto ("denom_secmod_cs_public_key",
&denom_cs_sm_pub),
GNUNET_JSON_pack_data_auto ("signkey_secmod_public_key",
&esign_sm_pub));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,

View File

@ -82,6 +82,42 @@ struct TEH_DenominationKey
};
struct TEH_SignDetails_RSA
{
/**
* message to sign
*/
const void *msg;
/**
* number of bytes in msg
*/
size_t msg_size;
};
struct TEH_SignDetails
{
/**
* Cipher type of the message
*/
enum TALER_DenominationCipher cipher;
union
{
/**
* If we use #TALER_DENOMINATION_RSA in @a cipher.
*/
struct TEH_SignDetails_RSA rsa_message;
/**
* If we use #TALER_DENOMINATION_CS in @a cipher.
*/
struct TALER_BlindedCsPlanchet cs_message;
} details;
};
/**
* Snapshot of the (coin and signing) keys (including private keys) of
* the exchange. There can be multiple instances of this struct, as it is
@ -179,11 +215,27 @@ TEH_keys_denomination_by_hash2 (struct TEH_KeyStateHandle *ksh,
*/
struct TALER_BlindedDenominationSignature
TEH_keys_denomination_sign (const struct TALER_DenominationHash *h_denom_pub,
const void *msg,
size_t msg_size,
const struct TEH_SignDetails *msg,
enum TALER_ErrorCode *ec);
/**
* Request to derive CS r_pub using the denomination corresponding to @a h_denom_pub
* and @a nonce.
*
* @param h_denom_pub hash of the public key to use to derive r_pub
* @param nonce withdraw/refresh nonce
* @param[out] ec set to the error code (or #TALER_EC_NONE on success)
* @return r_pub, the value inside the structure will be NULL on failure,
* see @a ec for details about the failure
*/
enum TALER_ErrorCode
TEH_keys_denomination_cs_r_pub (const struct
TALER_DenominationHash *h_denom_pub,
const struct TALER_CsNonce *nonce,
struct TALER_DenominationCSPublicRPairP *r_pub);
/**
* Revoke the public key associated with @param h_denom_pub .
* This function should be called AFTER the database was

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014-2021 Taler Systems SA
Copyright (C) 2014-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
@ -183,6 +183,7 @@ melt_transaction (void *cls,
}
if (! balance_ok)
{
GNUNET_break_op (0);
TEH_plugin->rollback (TEH_plugin->cls);
*mhd_ret
= TEH_RESPONSE_reply_coin_insufficient_funds (
@ -299,6 +300,9 @@ check_melt_valid (struct MHD_Connection *connection,
rmc->coin_refresh_fee = dk->meta.fee_refresh;
rmc->coin_value = dk->meta.value;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Melted coin's denomination is worth %s\n",
TALER_amount2s (&dk->meta.value));
/* sanity-check that "total melt amount > melt fee" */
if (0 <
TALER_amount_cmp (&rmc->coin_refresh_fee,

View File

@ -241,18 +241,17 @@ verify_and_execute_recoup_refresh (
}
{
void *coin_ev;
size_t coin_ev_size;
struct TALER_CoinPubHash c_hash;
struct TALER_BlindedPlanchet blinded_planchet;
if (GNUNET_OK !=
TALER_denom_blind (&dk->denom_pub,
coin_bks,
NULL, /* FIXME-Oec: TALER_AgeHash * */
&coin->coin_pub,
NULL, /* FIXME: Implement CS */
&c_hash,
&coin_ev,
&coin_ev_size))
&blinded_planchet))
{
GNUNET_break (0);
return TALER_MHD_reply_with_error (
@ -261,10 +260,10 @@ verify_and_execute_recoup_refresh (
TALER_EC_EXCHANGE_RECOUP_REFRESH_BLINDING_FAILED,
NULL);
}
TALER_coin_ev_hash (coin_ev,
coin_ev_size,
TALER_coin_ev_hash (&blinded_planchet,
&coin->denom_pub_hash,
&h_blind);
GNUNET_free (coin_ev);
TALER_blinded_planchet_free (&blinded_planchet);
}
pc.coin_sig = coin_sig;

View File

@ -243,18 +243,17 @@ verify_and_execute_recoup (
}
{
void *coin_ev;
size_t coin_ev_size;
struct TALER_CoinPubHash c_hash;
struct TALER_BlindedPlanchet blinded_planchet;
if (GNUNET_OK !=
TALER_denom_blind (&dk->denom_pub,
coin_bks,
NULL, /* FIXME-Oec: TALER_AgeHash * */
&coin->coin_pub,
NULL, /* FIXME: handle CS */
&c_hash,
&coin_ev,
&coin_ev_size))
&blinded_planchet))
{
GNUNET_break (0);
return TALER_MHD_reply_with_error (
@ -263,10 +262,17 @@ verify_and_execute_recoup (
TALER_EC_EXCHANGE_RECOUP_BLINDING_FAILED,
NULL);
}
TALER_coin_ev_hash (coin_ev,
coin_ev_size,
&pc.h_blind);
GNUNET_free (coin_ev);
if (GNUNET_OK != TALER_coin_ev_hash (&blinded_planchet,
&coin->denom_pub_hash,
&pc.h_blind))
{
GNUNET_break (0);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
NULL);
}
TALER_blinded_planchet_free (&blinded_planchet);
}
pc.coin_sig = coin_sig;

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014-2019, 2021 Taler Systems SA
Copyright (C) 2014-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
@ -31,12 +31,6 @@
#include "taler-exchange-httpd_keys.h"
/**
* Maximum number of fresh coins we allow per refresh operation.
*/
#define MAX_FRESH_COINS 256
/**
* Send a response for "/refreshes/$RCH/reveal".
*
@ -180,21 +174,33 @@ check_commitment (struct RevealContext *rctx,
for (unsigned int j = 0; j<rctx->num_fresh_coins; j++)
{
struct TALER_RefreshCoinData *rcd = &rce->new_coins[j];
struct TALER_PlanchetSecretsP ps;
struct TALER_CoinSpendPrivateKeyP coin_priv;
union TALER_DenominationBlindingKeyP bks;
struct TALER_ExchangeWithdrawValues alg_values;
struct TALER_PlanchetDetail pd;
struct TALER_CoinPubHash c_hash;
struct TALER_PlanchetSecretsP ps;
rcd->dk = &rctx->dks[j]->denom_pub;
TALER_planchet_setup_refresh (&ts,
TALER_transfer_secret_to_planchet_secret (&ts,
j,
&ps);
// TODO: implement cipher handling
alg_values.cipher = TALER_DENOMINATION_RSA;
TALER_planchet_setup_coin_priv (&ps,
&alg_values,
&coin_priv);
TALER_planchet_blinding_secret_create (&ps,
&alg_values,
&bks);
GNUNET_assert (GNUNET_OK ==
TALER_planchet_prepare (rcd->dk,
&ps,
&alg_values,
&bks,
&coin_priv,
&c_hash,
&pd));
rcd->coin_ev = pd.coin_ev;
rcd->coin_ev_size = pd.coin_ev_size;
rcd->blinded_planchet = pd.blinded_planchet;
}
}
}
@ -216,7 +222,7 @@ check_commitment (struct RevealContext *rctx,
{
struct TALER_RefreshCoinData *rcd = &rce->new_coins[j];
GNUNET_free (rcd->coin_ev);
TALER_blinded_planchet_free (&rcd->blinded_planchet);
}
GNUNET_free (rce->new_coins);
}
@ -296,7 +302,7 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,
const json_t *coin_evs)
{
unsigned int num_fresh_coins = json_array_size (new_denoms_h_json);
/* We know num_fresh_coins is bounded by #MAX_FRESH_COINS, so this is safe */
/* We know num_fresh_coins is bounded by #TALER_MAX_FRESH_COINS, so this is safe */
const struct TEH_DenominationKey *dks[num_fresh_coins];
struct TALER_RefreshCoinData rcds[num_fresh_coins];
struct TALER_EXCHANGEDB_RefreshRevealedCoin rrcs[num_fresh_coins];
@ -375,9 +381,8 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,
{
struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrc = &rrcs[i];
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_varsize (NULL,
&rrc->coin_ev,
&rrc->coin_ev_size),
TALER_JSON_spec_blinded_planchet (NULL,
&rrc->blinded_planchet),
GNUNET_JSON_spec_end ()
};
enum GNUNET_GenericReturnValue res;
@ -390,12 +395,12 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,
if (GNUNET_OK != res)
{
for (unsigned int j = 0; j<i; j++)
GNUNET_free (rrcs[j].coin_ev);
TALER_blinded_planchet_free (&rrcs[j].blinded_planchet);
return (GNUNET_NO == res) ? MHD_YES : MHD_NO;
}
GNUNET_CRYPTO_hash (rrc->coin_ev,
rrc->coin_ev_size,
&rrc->coin_envelope_hash.hash);
TALER_coin_ev_hash (&rrc->blinded_planchet,
&rrcs[i].h_denom_pub,
&rrc->coin_envelope_hash);
}
/* lookup old_coin_pub in database */
@ -485,9 +490,18 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,
const struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrc = &rrcs[i];
struct TALER_RefreshCoinData *rcd = &rcds[i];
rcd->coin_ev = rrc->coin_ev;
rcd->coin_ev_size = rrc->coin_ev_size;
rcd->blinded_planchet = rrc->blinded_planchet;
rcd->dk = &dks[i]->denom_pub;
if (rcd->blinded_planchet.cipher != rcd->dk->cipher)
{
GNUNET_break_op (0);
ret = TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_BAD_REQUEST,
TALER_JSON_pack_ec (
TALER_EC_EXCHANGE_GENERIC_CIPHER_MISMATCH));
goto cleanup;
}
}
rctx->dks = dks;
rctx->rcds = rcds;
@ -504,12 +518,18 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,
for (unsigned int i = 0; i<rctx->num_fresh_coins; i++)
{
enum TALER_ErrorCode ec = TALER_EC_NONE;
struct TEH_SignDetails sign_details;
const struct TALER_BlindedRsaPlanchet *rp;
// FIXME: implement cipher handling
rp = &rcds[i].blinded_planchet.details.rsa_blinded_planchet;
sign_details.cipher = TALER_DENOMINATION_RSA;
sign_details.details.rsa_message.msg = rp->blinded_msg;
sign_details.details.rsa_message.msg_size = rp->blinded_msg_size;
rrcs[i].coin_sig
= TEH_keys_denomination_sign (
&rrcs[i].h_denom_pub,
rcds[i].coin_ev,
rcds[i].coin_ev_size,
&sign_details,
&ec);
if (TALER_EC_NONE != ec)
{
@ -530,8 +550,7 @@ resolve_refreshes_reveal_denominations (struct MHD_Connection *connection,
{
struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrc = &rrcs[i];
rrc->coin_ev = rcds[i].coin_ev;
rrc->coin_ev_size = rcds[i].coin_ev_size;
rrc->blinded_planchet = rcds[i].blinded_planchet;
}
qs = TEH_plugin->insert_refresh_reveal (TEH_plugin->cls,
melt_serial_id,
@ -564,7 +583,7 @@ cleanup:
struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrc = &rrcs[i];
TALER_blinded_denom_sig_free (&rrc->coin_sig);
GNUNET_free (rrc->coin_ev);
TALER_blinded_planchet_free (&rrc->blinded_planchet);
}
return ret;
}
@ -597,7 +616,7 @@ handle_refreshes_reveal_json (struct MHD_Connection *connection,
unsigned int num_tprivs = json_array_size (tp_json);
GNUNET_assert (num_tprivs == TALER_CNC_KAPPA - 1); /* checked just earlier */
if ( (num_fresh_coins >= MAX_FRESH_COINS) ||
if ( (num_fresh_coins >= TALER_MAX_FRESH_COINS) ||
(0 == num_fresh_coins) )
{
GNUNET_break_op (0);

View File

@ -491,6 +491,53 @@ TEH_RESPONSE_reply_expired_denom_pub_hash (
}
MHD_RESULT
TEH_RESPONSE_reply_invalid_denom_cipher_for_operation (
struct MHD_Connection *connection,
const struct TALER_DenominationHash *dph)
{
struct TALER_ExchangePublicKeyP epub;
struct TALER_ExchangeSignatureP esig;
struct GNUNET_TIME_Timestamp now;
enum TALER_ErrorCode ec;
now = GNUNET_TIME_timestamp_get ();
{
struct TALER_DenominationUnknownAffirmationPS dua = {
.purpose.size = htonl (sizeof (dua)),
.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_AFFIRM_DENOM_UNKNOWN),
.timestamp = GNUNET_TIME_timestamp_hton (now),
.h_denom_pub = *dph,
};
ec = TEH_keys_exchange_sign (&dua,
&epub,
&esig);
}
if (TALER_EC_NONE != ec)
{
GNUNET_break (0);
return TALER_MHD_reply_with_error (connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
ec,
NULL);
}
return TALER_MHD_REPLY_JSON_PACK (
connection,
MHD_HTTP_NOT_FOUND,
TALER_JSON_pack_ec (
TALER_EC_EXCHANGE_GENERIC_INVALID_DENOMINATION_CIPHER_FOR_OPERATION),
GNUNET_JSON_pack_timestamp ("timestamp",
now),
GNUNET_JSON_pack_data_auto ("exchange_pub",
&epub),
GNUNET_JSON_pack_data_auto ("exchange_sig",
&esig),
GNUNET_JSON_pack_data_auto ("h_denom_pub",
dph));
}
/**
* Send proof that a request is invalid to client because of
* insufficient funds. This function will create a message with all

View File

@ -79,6 +79,19 @@ TEH_RESPONSE_reply_expired_denom_pub_hash (
const char *oper);
/**
* Send assertion that the given denomination cannot be used for this operation.
*
* @param connection connection to the client
* @param dph denomination public key hash
* @return MHD result code
*/
MHD_RESULT
TEH_RESPONSE_reply_invalid_denom_cipher_for_operation (
struct MHD_Connection *connection,
const struct TALER_DenominationHash *dph);
/**
* Send proof that a request is invalid to client because of
* insufficient funds. This function will create a message with all

View File

@ -98,12 +98,7 @@ struct WithdrawContext
/**
* Blinded planchet.
*/
void *blinded_msg;
/**
* Number of bytes in @e blinded_msg.
*/
size_t blinded_msg_len;
struct TALER_BlindedPlanchet blinded_planchet;
/**
* Set to the resulting signed coin data to be returned to the client.
@ -324,13 +319,12 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
{
struct WithdrawContext wc;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_varsize ("coin_ev",
&wc.blinded_msg,
&wc.blinded_msg_len),
GNUNET_JSON_spec_fixed_auto ("reserve_sig",
&wc.collectable.reserve_sig),
GNUNET_JSON_spec_fixed_auto ("denom_pub_hash",
&wc.collectable.denom_pub_hash),
TALER_JSON_spec_blinded_planchet ("coin_ev",
&wc.blinded_planchet),
GNUNET_JSON_spec_end ()
};
enum TALER_ErrorCode ec;
@ -444,6 +438,15 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
GNUNET_JSON_parse_free (spec);
return mret;
}
if (dk->denom_pub.cipher != wc.blinded_planchet.cipher)
{
/* denomination cipher and blinded planchet cipher not the same */
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_BAD_REQUEST,
TALER_EC_EXCHANGE_GENERIC_CIPHER_MISMATCH,
NULL);
}
}
if (0 >
@ -468,9 +471,17 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
= htonl (TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW);
wc.wsrd.h_denomination_pub
= wc.collectable.denom_pub_hash;
TALER_coin_ev_hash (wc.blinded_msg,
wc.blinded_msg_len,
&wc.wsrd.h_coin_envelope);
if (GNUNET_OK != TALER_coin_ev_hash (&wc.blinded_planchet,
&wc.collectable.denom_pub_hash,
&wc.wsrd.h_coin_envelope))
{
GNUNET_break (0);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_INTERNAL_SERVER_ERROR,
TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
NULL);
}
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (
TALER_SIGNATURE_WALLET_RESERVE_WITHDRAW,
@ -487,13 +498,38 @@ TEH_handler_withdraw (struct TEH_RequestContext *rc,
NULL);
}
// TODO: if CS: check nonce for reuse
/* Sign before transaction! */
ec = TALER_EC_NONE;
wc.collectable.sig
= TEH_keys_denomination_sign (&wc.collectable.denom_pub_hash,
wc.blinded_msg,
wc.blinded_msg_len,
{
struct TEH_SignDetails sign_details;
sign_details.cipher = wc.blinded_planchet.cipher;
switch (wc.blinded_planchet.cipher)
{
case TALER_DENOMINATION_RSA:
sign_details.details.rsa_message.msg =
wc.blinded_planchet.details.rsa_blinded_planchet.blinded_msg;
sign_details.details.rsa_message.msg_size =
wc.blinded_planchet.details.rsa_blinded_planchet.blinded_msg_size;
break;
case TALER_DENOMINATION_CS:
sign_details.details.cs_message =
wc.blinded_planchet.details.cs_blinded_planchet;
break;
default:
GNUNET_break (0);
GNUNET_JSON_parse_free (spec);
return TALER_MHD_reply_with_error (rc->connection,
MHD_HTTP_FORBIDDEN,
TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
NULL);
}
wc.collectable.sig = TEH_keys_denomination_sign (
&wc.collectable.denom_pub_hash,
&sign_details,
&ec);
}
if (TALER_EC_NONE != ec)
{
GNUNET_break (0);

View File

@ -70,7 +70,7 @@ PASSWORD = x
WIRE_GATEWAY_URL = "http://localhost:8082/3/"
# Coins for the tests.
[coin_eur_ct_1]
[coin_eur_ct_1_rsa]
value = EUR:0.01
duration_withdraw = 7 days
duration_spend = 2 years
@ -79,9 +79,21 @@ fee_withdraw = EUR:0.00
fee_deposit = EUR:0.00
fee_refresh = EUR:0.01
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_eur_ct_10]
[coin_eur_ct_1_cs]
value = EUR:0.01
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.00
fee_deposit = EUR:0.00
fee_refresh = EUR:0.01
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_ct_10_rsa]
value = EUR:0.10
duration_withdraw = 7 days
duration_spend = 2 years
@ -90,9 +102,21 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_eur_1]
[coin_eur_ct_10_cs]
value = EUR:0.10
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_1_rsa]
value = EUR:1
duration_withdraw = 7 days
duration_spend = 2 years
@ -101,4 +125,16 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_eur_1_cs]
value = EUR:1
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS

View File

@ -70,7 +70,7 @@ TALER_BANK_AUTH_METHOD = NONE
# Coins for the tests.
[coin_eur_ct_1]
[coin_eur_ct_1_rsa]
value = EUR:0.01
duration_withdraw = 7 days
duration_spend = 2 years
@ -79,9 +79,21 @@ fee_withdraw = EUR:0.00
fee_deposit = EUR:0.00
fee_refresh = EUR:0.01
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_eur_ct_10]
[coin_eur_ct_1_cs]
value = EUR:0.01
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.00
fee_deposit = EUR:0.00
fee_refresh = EUR:0.01
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_ct_10_rsa]
value = EUR:0.10
duration_withdraw = 7 days
duration_spend = 2 years
@ -90,9 +102,21 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_eur_1]
[coin_eur_ct_10_cs]
value = EUR:0.10
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_1_rsa]
value = EUR:1
duration_withdraw = 7 days
duration_spend = 2 years
@ -101,4 +125,16 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_eur_1_cs]
value = EUR:1
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS

View File

@ -6094,8 +6094,7 @@ postgres_insert_refresh_reveal (
GNUNET_PQ_query_param_uint32 (&i),
GNUNET_PQ_query_param_auto_from_type (&rrc->orig_coin_link_sig),
GNUNET_PQ_query_param_auto_from_type (&rrc->h_denom_pub),
GNUNET_PQ_query_param_fixed_size (rrc->coin_ev,
rrc->coin_ev_size),
TALER_PQ_query_param_blinded_planchet (&rrc->blinded_planchet),
GNUNET_PQ_query_param_auto_from_type (&rrc->coin_envelope_hash),
TALER_PQ_query_param_blinded_denom_sig (&rrc->coin_sig),
GNUNET_PQ_query_param_end
@ -6202,15 +6201,14 @@ add_revealed_coins (void *cls,
&rrc->orig_coin_link_sig),
GNUNET_PQ_result_spec_auto_from_type ("h_coin_ev",
&rrc->coin_envelope_hash),
GNUNET_PQ_result_spec_variable_size ("coin_ev",
(void **) &rrc->coin_ev,
&rrc->coin_ev_size),
TALER_PQ_result_spec_blinded_planchet ("coin_ev",
&rrc->blinded_planchet),
TALER_PQ_result_spec_blinded_denom_sig ("ev_sig",
&rrc->coin_sig),
GNUNET_PQ_result_spec_end
};
if (NULL != rrc->coin_ev)
if (TALER_DENOMINATION_INVALID != rrc->blinded_planchet.cipher)
{
/* duplicate offset, not allowed */
GNUNET_break (0);
@ -6293,10 +6291,9 @@ cleanup:
struct TALER_EXCHANGEDB_RefreshRevealedCoin *rrc = &grctx.rrcs[i];
TALER_blinded_denom_sig_free (&rrc->coin_sig);
GNUNET_free (rrc->coin_ev);
TALER_blinded_planchet_free (&rrc->blinded_planchet);
}
GNUNET_free (grctx.rrcs);
return qs;
}
@ -7212,7 +7209,7 @@ postgres_lookup_transfer_by_deposit (
GNUNET_PQ_query_param_end
};
char *payto_uri;
struct TALER_WireSalt wire_salt;
struct TALER_WireSaltP wire_salt;
struct GNUNET_PQ_ResultSpec rs[] = {
GNUNET_PQ_result_spec_auto_from_type ("wtid_raw",
wtid),

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014-2021 Taler Systems SA
Copyright (C) 2014-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@ -433,10 +433,9 @@ check_refresh_reveal_cb (
&revealed_coins[cnt];
const struct TALER_EXCHANGEDB_RefreshRevealedCoin *bcoin = &rrcs[cnt];
GNUNET_assert (acoin->coin_ev_size == bcoin->coin_ev_size);
GNUNET_assert (0 ==
GNUNET_memcmp (acoin->coin_ev,
bcoin->coin_ev));
TALER_blinded_planchet_cmp (&acoin->blinded_planchet,
&bcoin->blinded_planchet));
GNUNET_assert (0 ==
GNUNET_memcmp (&acoin->h_denom_pub,
&bcoin->h_denom_pub));
@ -531,7 +530,7 @@ handle_link_data_cb (void *cls,
break;
}
}
GNUNET_assert (found);
GNUNET_assert (GNUNET_NO != found);
}
}
@ -1345,8 +1344,7 @@ run (void *cls)
unsigned int cnt;
enum GNUNET_DB_QueryStatus qs;
struct GNUNET_TIME_Timestamp now;
struct TALER_WireSalt salt;
union TALER_DenominationBlindingKeyP bks;
struct TALER_WireSaltP salt;
struct TALER_CoinPubHash c_hash;
uint64_t known_coin_id;
uint64_t rrc_serial;
@ -1354,6 +1352,13 @@ run (void *cls)
struct TALER_DenominationPublicKey *new_denom_pubs = NULL;
uint64_t reserve_out_serial_id;
uint64_t melt_serial_id;
struct TALER_PlanchetSecretsP ps;
union TALER_DenominationBlindingKeyP bks;
struct TALER_ExchangeWithdrawValues alg_values = {
/* RSA is simpler, and for the DB there is no real difference between
CS and RSA, just one should be used, so we use RSA */
.cipher = TALER_DENOMINATION_RSA
};
memset (&deposit,
0,
@ -1415,7 +1420,6 @@ run (void *cls)
GNUNET_assert (GNUNET_OK ==
TALER_string_to_amount (CURRENCY ":1.000010",
&amount_with_fee));
result = 4;
now = GNUNET_TIME_timestamp_get ();
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
@ -1464,36 +1468,42 @@ run (void *cls)
TALER_denom_pub_hash (&dkp->pub,
&cbc.denom_pub_hash);
RND_BLK (&cbc.reserve_sig);
TALER_planchet_blinding_secret_create (&ps,
&alg_values,
&bks);
{
struct TALER_PlanchetDetail pd;
struct TALER_CoinSpendPublicKeyP coin_pub;
struct TALER_AgeHash age_hash;
struct TALER_AgeHash *p_ah[2] = {NULL, &age_hash};
struct TALER_AgeHash *p_ah[2] = {
NULL,
&age_hash
};
// FIXME:
/* Call TALER_denom_blind()/TALER_denom_sign_blinded() twice, once without
* age_hash, once with age_hash */
RND_BLK (&age_hash);
for (size_t i = 0; i < sizeof(p_ah) / sizeof(p_ah[0]); i++)
{
RND_BLK (&coin_pub);
TALER_blinding_secret_create (&bks);
GNUNET_assert (GNUNET_OK ==
TALER_denom_blind (&dkp->pub,
&bks,
p_ah[i],
&coin_pub,
&alg_values,
&c_hash,
&pd.coin_ev,
&pd.coin_ev_size));
TALER_coin_ev_hash (pd.coin_ev,
pd.coin_ev_size,
&cbc.h_coin_envelope);
&pd.blinded_planchet));
GNUNET_assert (GNUNET_OK ==
TALER_coin_ev_hash (&pd.blinded_planchet,
&cbc.denom_pub_hash,
&cbc.h_coin_envelope));
GNUNET_assert (GNUNET_OK ==
TALER_denom_sign_blinded (&cbc.sig,
&dkp->priv,
pd.coin_ev,
pd.coin_ev_size));
GNUNET_free (pd.coin_ev);
&pd.blinded_planchet));
TALER_blinded_planchet_free (&pd.blinded_planchet);
}
}
@ -1724,6 +1734,8 @@ run (void *cls)
{
struct TALER_EXCHANGEDB_RefreshRevealedCoin *ccoin;
struct GNUNET_TIME_Timestamp now;
struct TALER_BlindedRsaPlanchet *rp;
struct TALER_BlindedPlanchet *bp;
now = GNUNET_TIME_timestamp_get ();
new_dkp[cnt] = create_denom_key_pair (RSA_KEY_SIZE,
@ -1736,23 +1748,25 @@ run (void *cls)
GNUNET_assert (NULL != new_dkp[cnt]);
new_denom_pubs[cnt] = new_dkp[cnt]->pub;
ccoin = &revealed_coins[cnt];
ccoin->coin_ev_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 (
bp = &ccoin->blinded_planchet;
bp->cipher = TALER_DENOMINATION_RSA;
rp = &bp->details.rsa_blinded_planchet;
rp->blinded_msg_size = 1 + (size_t) GNUNET_CRYPTO_random_u64 (
GNUNET_CRYPTO_QUALITY_WEAK,
(RSA_KEY_SIZE / 8) - 1);
ccoin->coin_ev = GNUNET_malloc (ccoin->coin_ev_size);
rp->blinded_msg = GNUNET_malloc (rp->blinded_msg_size);
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
ccoin->coin_ev,
ccoin->coin_ev_size);
GNUNET_CRYPTO_hash (ccoin->coin_ev,
ccoin->coin_ev_size,
&ccoin->coin_envelope_hash.hash);
rp->blinded_msg,
rp->blinded_msg_size);
TALER_denom_pub_hash (&new_dkp[cnt]->pub,
&ccoin->h_denom_pub);
TALER_coin_ev_hash (bp,
&ccoin->h_denom_pub,
&ccoin->coin_envelope_hash);
GNUNET_assert (GNUNET_OK ==
TALER_denom_sign_blinded (&ccoin->coin_sig,
&new_dkp[cnt]->priv,
ccoin->coin_ev,
ccoin->coin_ev_size));
bp));
}
RND_BLK (&tprivs);
RND_BLK (&tpub);
@ -1772,11 +1786,13 @@ run (void *cls)
{
struct TALER_BlindedCoinHash h_coin_ev;
struct TALER_CoinSpendPublicKeyP ocp;
struct TALER_DenominationHash denom_hash;
GNUNET_CRYPTO_hash (revealed_coins[0].coin_ev,
revealed_coins[0].coin_ev_size,
&h_coin_ev.hash);
TALER_denom_pub_hash (&new_denom_pubs[0],
&denom_hash);
TALER_coin_ev_hash (&revealed_coins[0].blinded_planchet,
&denom_hash,
&h_coin_ev);
FAILIF (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT !=
plugin->get_old_coin_by_h_blind (plugin->cls,
&h_coin_ev,
@ -2385,7 +2401,7 @@ drop:
for (unsigned int cnt = 0; cnt < MELT_NEW_COINS; cnt++)
{
TALER_blinded_denom_sig_free (&revealed_coins[cnt].coin_sig);
GNUNET_free (revealed_coins[cnt].coin_ev);
TALER_blinded_planchet_free (&revealed_coins[cnt].blinded_planchet);
}
GNUNET_free (revealed_coins);
revealed_coins = NULL;

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014-2021 Taler Systems SA
Copyright (C) 2014-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU Affero General Public License as published by the Free Software
@ -922,7 +922,7 @@ TALER_EXCHANGE_deposit (
const struct TALER_Amount *amount,
struct GNUNET_TIME_Timestamp wire_deadline,
const char *merchant_payto_uri,
const struct TALER_WireSalt *wire_salt,
const struct TALER_WireSaltP *wire_salt,
const struct TALER_PrivateContractHash *h_contract_terms,
const json_t *extension_details,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
@ -1033,6 +1033,119 @@ void
TALER_EXCHANGE_refund_cancel (struct TALER_EXCHANGE_RefundHandle *refund);
/* ********************* POST /csr *********************** */
/**
* @brief A /csr Handle
*/
struct TALER_EXCHANGE_CsRHandle;
/**
* Details about a response for a CS R request.
*/
struct TALER_EXCHANGE_CsRResponse
{
/**
* HTTP response data.
*/
struct TALER_EXCHANGE_HttpResponse hr;
/**
* Details about the response.
*/
union
{
/**
* Details if the status is #MHD_HTTP_OK.
*/
struct
{
/**
* Length of the @e alg_values array.
*/
unsigned int alg_values_len;
/**
* Values contributed by the exchange for the
* respective coin's withdraw operation.
*/
const struct TALER_ExchangeWithdrawValues *alg_values;
} success;
/**
* Details if the status is #MHD_HTTP_GONE.
*/
struct
{
/* TODO: returning full details is not implemented */
} gone;
} details;
};
/**
* Callbacks of this type are used to serve the result of submitting a
* CS R request to a exchange.
*
* @param cls closure
* @param csrr response details
*/
typedef void
(*TALER_EXCHANGE_CsRCallback) (void *cls,
const struct TALER_EXCHANGE_CsRResponse *csrr);
/**
* Information we pass per coin to a /csr request.
*/
struct TALER_EXCHANGE_NonceKey
{
/**
* Which denomination key is the /csr request for?
*/
const struct TALER_EXCHANGE_DenomPublicKey *pk;
/**
* What is the client nonce for the request?
*/
struct TALER_CsNonce nonce;
};
/**
* Get a CS R using a /csr request.
*
* @param exchange the exchange handle; the exchange must be ready to operate
* @param nks_len length of the @a nks array
* @param nks array of denominations and nonces
* @param res_cb the callback to call when the final result for this request is available
* @param res_cb_cls closure for the above callback
* @return handle for the operation on success, NULL on error, i.e.
* if the inputs are invalid (i.e. denomination key not with this exchange).
* In this case, the callback is not called.
*/
struct TALER_EXCHANGE_CsRHandle *
TALER_EXCHANGE_csr (struct TALER_EXCHANGE_Handle *exchange,
unsigned int nks_len,
struct TALER_EXCHANGE_NonceKey *nks,
TALER_EXCHANGE_CsRCallback res_cb,
void *res_cb_cls);
/**
*
* Cancel a CS R request. This function cannot be used
* on a request handle if a response is already served for it.
*
* @param csrh the withdraw handle
*/
void
TALER_EXCHANGE_csr_cancel (struct TALER_EXCHANGE_CsRHandle *csrh);
/* ********************* GET /reserves/$RESERVE_PUB *********************** */
@ -1293,10 +1406,27 @@ struct TALER_EXCHANGE_WithdrawResponse
*/
struct
{
/**
* Private key of the coin.
*/
struct TALER_CoinSpendPrivateKeyP coin_priv;
/**
* Value used to blind the key for the signature.
* Needed for recoup operations.
*/
union TALER_DenominationBlindingKeyP bks;
/**
* Signature over the coin.
*/
struct TALER_DenominationSignature sig;
/**
* Values contributed from the exchange during the
* withdraw protocol.
*/
struct TALER_ExchangeWithdrawValues exchange_vals;
} success;
/**
@ -1451,50 +1581,45 @@ TALER_EXCHANGE_withdraw2_cancel (struct TALER_EXCHANGE_Withdraw2Handle *wh);
/**
* Melt (partially spent) coins to obtain fresh coins that are
* unlinkable to the original coin(s). Note that melting more
* than one coin in a single request will make those coins linkable,
* so the safest operation only melts one coin at a time.
*
* This API is typically used by a wallet. Note that to ensure that
* no money is lost in case of hardware failures, is operation does
* not actually initiate the request. Instead, it generates a buffer
* which the caller must store before proceeding with the actual call
* to #TALER_EXCHANGE_melt() that will generate the request.
*
* This function does verify that the given request data is internally
* consistent. However, the @a melts_sigs are NOT verified.
*
* Aside from some non-trivial cryptographic operations that might
* take a bit of CPU time to complete, this function returns
* its result immediately and does not start any asynchronous
* processing. This function is also thread-safe.
*
* @param melt_priv private keys of the coin to melt
* @param melt_amount amount specifying how much
* the coin will contribute to the melt (including fee)
* @param melt_sig signatures affirming the
* validity of the public keys corresponding to the
* @a melt_priv private key
* @param melt_pk denomination key information
* record corresponding to the @a melt_sig
* validity of the keys
* @param fresh_pks_len length of the @a pks array
* @param fresh_pks array of @a pks_len denominations of fresh coins to create
* @return NULL
* if the inputs are invalid (i.e. denomination key not with this exchange).
* Otherwise, JSON data structure to store persistently
* before proceeding to #TALER_EXCHANGE_melt().
* Non-null results should be freed using GNUNET_free().
* Information needed to melt (partially spent) coins to obtain fresh coins
* that are unlinkable to the original coin(s). Note that melting more than
* one coin in a single request will make those coins linkable, so we only melt one coin at a time.
*/
json_t *
TALER_EXCHANGE_refresh_prepare (
const struct TALER_CoinSpendPrivateKeyP *melt_priv,
const struct TALER_Amount *melt_amount,
const struct TALER_DenominationSignature *melt_sig,
const struct TALER_EXCHANGE_DenomPublicKey *melt_pk,
unsigned int fresh_pks_len,
const struct TALER_EXCHANGE_DenomPublicKey *fresh_pks);
struct TALER_EXCHANGE_RefreshData
{
/**
* private key of the coin to melt
*/
struct TALER_CoinSpendPrivateKeyP melt_priv;
/**
* amount specifying how much the coin will contribute to the melt
* (including fee)
*/
struct TALER_Amount melt_amount;
/**
* signatures affirming the validity of the public keys corresponding to the
* @e melt_priv private key
*/
struct TALER_DenominationSignature melt_sig;
/**
* denomination key information record corresponding to the @e melt_sig
* validity of the keys
*/
struct TALER_EXCHANGE_DenomPublicKey melt_pk;
/**
* array of @e pks_len denominations of fresh coins to create
*/
const struct TALER_EXCHANGE_DenomPublicKey *fresh_pks;
/**
* length of the @e pks array
*/
unsigned int fresh_pks_len;
};
/* ********************* /coins/$COIN_PUB/melt ***************************** */
@ -1513,6 +1638,9 @@ struct TALER_EXCHANGE_MeltHandle;
*
* @param cls closure
* @param hr HTTP response data
* @param num_coins number of fresh coins to be created, length of the @a exchange_vals array, 0 if the operation failed
* @param alg_values array @a num_coins of exchange values contributed to the refresh operation
* @param bks array of @a num_coins blinding keys used to blind the fresh coins
* @param noreveal_index choice by the exchange in the cut-and-choose protocol,
* UINT32_MAX on error
* @param sign_key exchange key used to sign @a full_response, or NULL
@ -1521,6 +1649,9 @@ typedef void
(*TALER_EXCHANGE_MeltCallback) (
void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr,
unsigned int num_coins,
const struct TALER_ExchangeWithdrawValues *alg_values,
const union TALER_DenominationBlindingKeyP *bks,
uint32_t noreveal_index,
const struct TALER_ExchangePublicKeyP *sign_key);
@ -1536,8 +1667,8 @@ typedef void
* prior to calling this function.
*
* @param exchange the exchange handle; the exchange must be ready to operate
* @param refresh_data the refresh data as returned from
#TALER_EXCHANGE_refresh_prepare())
* @param ps the fresh secret that defines the refresh operation
* @param rd the refresh data specifying the characteristics of the operation
* @param melt_cb the callback to call with the result
* @param melt_cb_cls closure for @a melt_cb
* @return a handle for this request; NULL if the argument was invalid.
@ -1545,7 +1676,8 @@ typedef void
*/
struct TALER_EXCHANGE_MeltHandle *
TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange,
const json_t *refresh_data,
const struct TALER_PlanchetSecretsP *ps,
const struct TALER_EXCHANGE_RefreshData *rd,
TALER_EXCHANGE_MeltCallback melt_cb,
void *melt_cb_cls);
@ -1574,6 +1706,7 @@ TALER_EXCHANGE_melt_cancel (struct TALER_EXCHANGE_MeltHandle *mh);
* @param cls closure
* @param hr HTTP response data
* @param num_coins number of fresh coins created, length of the @a sigs and @a coin_privs arrays, 0 if the operation failed
* @param exchange_vals array of contributions from the exchange on the refreshes
* @param coin_privs array of @a num_coins private keys for the coins that were created, NULL on error
* @param sigs array of signature over @a num_coins coins, NULL on error
*/
@ -1582,7 +1715,7 @@ typedef void
void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr,
unsigned int num_coins,
const struct TALER_PlanchetSecretsP *coin_privs,
const struct TALER_CoinSpendPrivateKeyP *coin_privs,
const struct TALER_DenominationSignature *sigs);
@ -1602,8 +1735,10 @@ struct TALER_EXCHANGE_RefreshesRevealHandle;
* prior to calling this function.
*
* @param exchange the exchange handle; the exchange must be ready to operate
* @param refresh_data the refresh data as returned from
#TALER_EXCHANGE_refresh_prepare())
* @param ps the fresh secret that defines the refresh operation
* @param rd the refresh data that characterizes the refresh operation
* @param num_coins number of fresh coins to be created, length of the @a exchange_vals array, must match value in @a rd
* @param alg_values array @a num_coins of exchange values contributed to the refresh operation
* @param noreveal_index response from the exchange to the
* #TALER_EXCHANGE_melt() invocation
* @param reveal_cb the callback to call with the final result of the
@ -1615,7 +1750,10 @@ struct TALER_EXCHANGE_RefreshesRevealHandle;
struct TALER_EXCHANGE_RefreshesRevealHandle *
TALER_EXCHANGE_refreshes_reveal (
struct TALER_EXCHANGE_Handle *exchange,
const json_t *refresh_data,
const struct TALER_PlanchetSecretsP *ps,
const struct TALER_EXCHANGE_RefreshData *rd,
unsigned int num_coins,
const struct TALER_ExchangeWithdrawValues *alg_values,
uint32_t noreveal_index,
TALER_EXCHANGE_RefreshesRevealCallback reveal_cb,
void *reveal_cb_cls);
@ -2034,6 +2172,7 @@ typedef void
* @param exchange the exchange handle; the exchange must be ready to operate
* @param pk kind of coin to pay back
* @param denom_sig signature over the coin by the exchange using @a pk
* @param exchange_vals contribution from the exchange on the withdraw
* @param ps secret internals of the original planchet
* @param recoup_cb the callback to call when the final result for this request is available
* @param recoup_cb_cls closure for @a recoup_cb
@ -2045,6 +2184,7 @@ struct TALER_EXCHANGE_RecoupHandle *
TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
const struct TALER_EXCHANGE_DenomPublicKey *pk,
const struct TALER_DenominationSignature *denom_sig,
const struct TALER_ExchangeWithdrawValues *exchange_vals,
const struct TALER_PlanchetSecretsP *ps,
TALER_EXCHANGE_RecoupResultCallback recoup_cb,
void *recoup_cb_cls);
@ -2094,7 +2234,8 @@ typedef void
* @param exchange the exchange handle; the exchange must be ready to operate
* @param pk kind of coin to pay back
* @param denom_sig signature over the coin by the exchange using @a pk
* @param ps secret internals of the original planchet
* @param exchange_vals contribution from the exchange on the withdraw
* @param ps secret internals of the original refresh-reveal operation
* @param recoup_cb the callback to call when the final result for this request is available
* @param recoup_cb_cls closure for @a recoup_cb
* @return NULL
@ -2106,6 +2247,7 @@ TALER_EXCHANGE_recoup_refresh (
struct TALER_EXCHANGE_Handle *exchange,
const struct TALER_EXCHANGE_DenomPublicKey *pk,
const struct TALER_DenominationSignature *denom_sig,
const struct TALER_ExchangeWithdrawValues *exchange_vals,
const struct TALER_PlanchetSecretsP *ps,
TALER_EXCHANGE_RecoupRefreshResultCallback recoup_cb,
void *recoup_cb_cls);
@ -2497,10 +2639,15 @@ struct TALER_EXCHANGE_FutureKeys
struct TALER_SecurityModulePublicKeyP signkey_secmod_public_key;
/**
* Public key of the denomination security module.
* Public key of the RSA denomination security module.
*/
struct TALER_SecurityModulePublicKeyP denom_secmod_public_key;
/**
* Public key of the CS denomination security module.
*/
struct TALER_SecurityModulePublicKeyP denom_secmod_cs_public_key;
/**
* Offline master public key used by this exchange.
*/

View File

@ -340,7 +340,7 @@ struct TALER_EXCHANGEDB_TableData
struct TALER_MerchantPublicKeyP merchant_pub;
struct TALER_PrivateContractHash h_contract_terms;
struct TALER_CoinSpendSignatureP coin_sig;
struct TALER_WireSalt wire_salt;
struct TALER_WireSaltP wire_salt;
uint64_t wire_target_serial_id;
bool tiny;
bool done;
@ -1027,7 +1027,7 @@ struct TALER_EXCHANGEDB_Deposit
/**
* Salt used by the merchant to compute "h_wire".
*/
struct TALER_WireSalt wire_salt;
struct TALER_WireSaltP wire_salt;
/**
* Information about the receiver for executing the transaction. URI in
@ -1126,7 +1126,7 @@ struct TALER_EXCHANGEDB_DepositListEntry
/**
* Salt used to compute h_wire from the @e receiver_wire_account.
*/
struct TALER_WireSalt wire_salt;
struct TALER_WireSaltP wire_salt;
/**
* Time when this request was generated. Used, for example, to
@ -1646,14 +1646,9 @@ struct TALER_EXCHANGEDB_RefreshRevealedCoin
struct TALER_BlindedDenominationSignature coin_sig;
/**
* Blinded message to be signed (in envelope), with @e coin_env_size bytes.
* Blinded message to be signed (in envelope).
*/
void *coin_ev;
/**
* Number of bytes in @e coin_ev.
*/
size_t coin_ev_size;
struct TALER_BlindedPlanchet blinded_planchet;
};

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014, 2015, 2016, 2021 Taler Systems SA
Copyright (C) 2014, 2015, 2016, 2021, 2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@ -117,6 +117,20 @@ TALER_JSON_pack_blinded_denom_sig (
const struct TALER_BlindedDenominationSignature *sig);
/**
* Generate packer instruction for a JSON field of type
* blinded planchet.
*
* @param name name of the field to add to the object
* @param blinded_planchet blinded planchet
* @return json pack specification
*/
struct GNUNET_JSON_PackSpec
TALER_JSON_pack_blinded_planchet (
const char *name,
const struct TALER_BlindedPlanchet *blinded_planchet);
/**
* Generate packer instruction for a JSON field of type
* amount.
@ -238,7 +252,7 @@ TALER_JSON_spec_denom_pub (const char *field,
* Generate line in parser specification for denomination signature.
*
* @param field name of the field
* @param sig the signature to initialize
* @param[out] sig the signature to initialize
* @return corresponding field spec
*/
struct GNUNET_JSON_Specification
@ -251,7 +265,7 @@ TALER_JSON_spec_denom_sig (const char *field,
* blinded denomination signature.
*
* @param field name of the field
* @param sig the blinded signature to initialize
* @param[out] sig the blinded signature to initialize
* @return corresponding field spec
*/
struct GNUNET_JSON_Specification
@ -260,6 +274,19 @@ TALER_JSON_spec_blinded_denom_sig (
struct TALER_BlindedDenominationSignature *sig);
/**
* Generate line in parser specification for a
* blinded planchet.
*
* @param field name of the field
* @param[out] blinded_planchet the blinded planchet to initialize
* @return corresponding field spec
*/
struct GNUNET_JSON_Specification
TALER_JSON_spec_blinded_planchet (const char *field,
struct TALER_BlindedPlanchet *blinded_planchet);
/**
* The expected field stores a possibly internationalized string.
* Internationalization means that there is another field "$name_i18n"
@ -563,6 +590,12 @@ enum GNUNET_GenericReturnValue
TALER_JSON_parse_agemask (const json_t *root,
struct TALER_AgeMask *mask);
/**
* Canonicalize a JSON input to a string according to RFC 8785.
*/
char *
TALER_JSON_canonicalize (const json_t *input);
#endif /* TALER_JSON_LIB_H_ */
/* End of taler_json_lib.h */

View File

@ -77,6 +77,19 @@ TALER_PQ_query_param_denom_sig (
const struct TALER_DenominationSignature *denom_sig);
/**
* Generate query parameter for a blinded planchet.
* Internally, various attributes of the blinded
* planchet will be serialized into on
* variable-size BLOB.
*
* @param x pointer to the query parameter to pass
*/
struct GNUNET_PQ_QueryParam
TALER_PQ_query_param_blinded_planchet (
const struct TALER_BlindedPlanchet *bp);
/**
* Generate query parameter for a blinded denomination signature. Internally,
* the various attributes of the signature will be serialized into on
@ -166,6 +179,19 @@ TALER_PQ_result_spec_blinded_denom_sig (
struct TALER_BlindedDenominationSignature *denom_sig);
/**
* Blinded planchet expected.
*
* @param name name of the field in the table
* @param[out] bp where to store the blinded planchet
* @return array entry for the result specification to use
*/
struct GNUNET_PQ_ResultSpec
TALER_PQ_result_spec_blinded_planchet (
const char *name,
struct TALER_BlindedPlanchet *bp);
/**
* json_t expected.
*

View File

@ -287,6 +287,11 @@
*/
#define TALER_SIGNATURE_SM_SIGNING_KEY 1251
/**
* Signature on a denomination key announcement.
*/
#define TALER_SIGNATURE_SM_CS_DENOMINATION_KEY 1252
/*******************/
/* Test signatures */
/*******************/
@ -341,7 +346,7 @@ struct TALER_DenominationKeyAnnouncementPS
/**
* Hash of the denomination public key.
*/
struct TALER_RsaPubHashP h_rsa;
struct TALER_DenominationHash h_denom;
/**
* Hash of the section name in the configuration of this denomination.

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
(C) 2018 Taler Systems SA
(C) 2018-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as
@ -2443,6 +2443,7 @@ TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits,
#define TALER_TESTING_SIMPLE_TRAITS(op) \
op (bank_row, const uint64_t) \
op (reserve_priv, const struct TALER_ReservePrivateKeyP) \
op (planchet_secret, const struct TALER_PlanchetSecretsP) \
op (reserve_pub, const struct TALER_ReservePublicKeyP) \
op (merchant_priv, const struct TALER_MerchantPrivateKeyP) \
op (merchant_pub, const struct TALER_MerchantPublicKeyP) \
@ -2482,6 +2483,8 @@ TALER_TESTING_get_trait (const struct TALER_TESTING_Trait *traits,
#define TALER_TESTING_INDEXED_TRAITS(op) \
op (denom_pub, const struct TALER_EXCHANGE_DenomPublicKey) \
op (denom_sig, const struct TALER_DenominationSignature) \
op (planchet_secrets, const struct TALER_PlanchetSecretsP) \
op (exchange_wd_value, const struct TALER_ExchangeWithdrawValues) \
op (coin_priv, const struct TALER_CoinSpendPrivateKeyP) \
op (coin_pub, const struct TALER_CoinSpendPublicKeyP) \
op (absolute_time, const struct GNUNET_TIME_Absolute) \

View File

@ -444,7 +444,7 @@ TALER_yna_to_string (enum TALER_EXCHANGE_YesNoAll yna);
* @param c the character to search for
* @return char* the first occurence of `c` in `s`
*/
char * strchrnul (const char *s, int c);
char *strchrnul (const char *s, int c);
#endif

View File

@ -78,27 +78,27 @@ lowdump (struct GNUNET_Buffer *buf,
{
case 0x8:
GNUNET_buffer_write (buf,
"\b",
"\\b",
2);
break;
case 0x9:
GNUNET_buffer_write (buf,
"\t",
"\\t",
2);
break;
case 0xA:
GNUNET_buffer_write (buf,
"\n",
"\\n",
2);
break;
case 0xC:
GNUNET_buffer_write (buf,
"\f",
"\\f",
2);
break;
case 0xD:
GNUNET_buffer_write (buf,
"\r",
"\\r",
2);
break;
default:
@ -144,6 +144,9 @@ rfc8785encode (char **inp)
if ( (1 == mbl) &&
(val <= 0x1F) )
{
/* Should not happen, as input is produced by
* JSON stringification */
GNUNET_break (0);
lowdump (&buf,
val);
}
@ -193,6 +196,12 @@ rfc8785encode (char **inp)
}
}
break;
default:
mbl = 2;
GNUNET_buffer_write (&buf,
pos,
mbl);
break;
}
}
else
@ -1009,6 +1018,24 @@ TALER_deposit_extension_hash (const json_t *extensions,
}
char *
TALER_JSON_canonicalize (const json_t *input)
{
char *wire_enc;
if (NULL == (wire_enc = json_dumps (input,
JSON_ENCODE_ANY
| JSON_COMPACT
| JSON_SORT_KEYS)))
{
GNUNET_break (0);
return NULL;
}
rfc8785encode (&wire_enc);
return wire_enc;
}
enum GNUNET_GenericReturnValue
TALER_JSON_extensions_config_hash (const json_t *config,
struct TALER_ExtensionConfigHash *ech)

View File

@ -262,6 +262,26 @@ parse_denom_pub (void *cls,
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (root,
ispec,
&emsg,
&eline))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
case TALER_DENOMINATION_CS:
{
struct GNUNET_JSON_Specification ispec[] = {
GNUNET_JSON_spec_fixed ("cs_public_key",
&denom_pub->details.cs_public_key,
sizeof (denom_pub->details.cs_public_key)),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (root,
ispec,
@ -357,6 +377,27 @@ parse_denom_sig (void *cls,
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (root,
ispec,
&emsg,
&eline))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
case TALER_DENOMINATION_CS:
{
struct GNUNET_JSON_Specification ispec[] = {
GNUNET_JSON_spec_fixed_auto ("cs_signature_r",
&denom_sig->details.cs_signature.r_point),
GNUNET_JSON_spec_fixed_auto ("cs_signature_s",
&denom_sig->details.cs_signature.s_scalar),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (root,
ispec,
@ -463,6 +504,29 @@ parse_blinded_denom_sig (void *cls,
}
return GNUNET_OK;
}
case TALER_DENOMINATION_CS:
{
struct GNUNET_JSON_Specification ispec[] = {
GNUNET_JSON_spec_uint32 ("b",
&denom_sig->details.blinded_cs_answer.b),
GNUNET_JSON_spec_fixed_auto ("s",
&denom_sig->details.blinded_cs_answer.
s_scalar),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (root,
ispec,
&emsg,
&eline))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
break;
default:
GNUNET_break_op (0);
return GNUNET_SYSERR;
@ -503,6 +567,129 @@ TALER_JSON_spec_blinded_denom_sig (
}
/**
* Parse given JSON object to blinded planchet.
*
* @param cls closure, NULL
* @param root the json object representing data
* @param[out] spec where to write the data
* @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
*/
static enum GNUNET_GenericReturnValue
parse_blinded_planchet (void *cls,
json_t *root,
struct GNUNET_JSON_Specification *spec)
{
struct TALER_BlindedPlanchet *blinded_planchet = spec->ptr;
uint32_t cipher;
struct GNUNET_JSON_Specification dspec[] = {
GNUNET_JSON_spec_uint32 ("cipher",
&cipher),
GNUNET_JSON_spec_end ()
};
const char *emsg;
unsigned int eline;
(void) cls;
if (GNUNET_OK !=
GNUNET_JSON_parse (root,
dspec,
&emsg,
&eline))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
blinded_planchet->cipher = (enum TALER_DenominationCipher) cipher;
switch (blinded_planchet->cipher)
{
case TALER_DENOMINATION_RSA:
{
struct GNUNET_JSON_Specification ispec[] = {
GNUNET_JSON_spec_varsize (
"rsa_blinded_planchet",
&blinded_planchet->details.rsa_blinded_planchet.blinded_msg,
&blinded_planchet->details.rsa_blinded_planchet.blinded_msg_size),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (root,
ispec,
&emsg,
&eline))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
case TALER_DENOMINATION_CS:
{
struct GNUNET_JSON_Specification ispec[] = {
GNUNET_JSON_spec_fixed_auto (
"cs_nonce",
&blinded_planchet->details.cs_blinded_planchet.nonce),
GNUNET_JSON_spec_fixed_auto (
"cs_blinded_c0",
&blinded_planchet->details.cs_blinded_planchet.c[0]),
GNUNET_JSON_spec_fixed_auto (
"cs_blinded_c1",
&blinded_planchet->details.cs_blinded_planchet.c[1]),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (root,
ispec,
&emsg,
&eline))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
}
break;
default:
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
}
/**
* Cleanup data left from parsing blinded planchet.
*
* @param cls closure, NULL
* @param[out] spec where to free the data
*/
static void
clean_blinded_planchet (void *cls,
struct GNUNET_JSON_Specification *spec)
{
struct TALER_BlindedPlanchet *blinded_planchet = spec->ptr;
(void) cls;
TALER_blinded_planchet_free (blinded_planchet);
}
struct GNUNET_JSON_Specification
TALER_JSON_spec_blinded_planchet (const char *field,
struct TALER_BlindedPlanchet *blinded_planchet)
{
struct GNUNET_JSON_Specification ret = {
.parser = &parse_blinded_planchet,
.cleaner = &clean_blinded_planchet,
.field = field,
.ptr = blinded_planchet
};
return ret;
}
/**
* Closure for #parse_i18n_string.
*/
@ -686,7 +873,6 @@ TALER_JSON_parse_agemask (const json_t *root,
{
return GNUNET_SYSERR;
}
return GNUNET_OK;
}

View File

@ -68,6 +68,17 @@ TALER_JSON_pack_denom_pub (
GNUNET_JSON_pack_rsa_public_key ("rsa_public_key",
pk->details.rsa_public_key));
break;
case TALER_DENOMINATION_CS:
ps.object
= GNUNET_JSON_PACK (
GNUNET_JSON_pack_uint64 ("cipher",
TALER_DENOMINATION_CS),
GNUNET_JSON_pack_uint64 ("age_mask",
pk->age_mask.mask),
GNUNET_JSON_pack_data_varsize ("cs_public_key",
&pk->details.cs_public_key,
sizeof (pk->details.cs_public_key)));
break;
default:
GNUNET_assert (0);
}
@ -87,13 +98,21 @@ TALER_JSON_pack_denom_sig (
switch (sig->cipher)
{
case TALER_DENOMINATION_RSA:
ps.object
= GNUNET_JSON_PACK (
ps.object = GNUNET_JSON_PACK (
GNUNET_JSON_pack_uint64 ("cipher",
TALER_DENOMINATION_RSA),
GNUNET_JSON_pack_rsa_signature ("rsa_signature",
sig->details.rsa_signature));
break;
case TALER_DENOMINATION_CS:
ps.object = GNUNET_JSON_PACK (
GNUNET_JSON_pack_uint64 ("cipher",
TALER_DENOMINATION_CS),
GNUNET_JSON_pack_data_auto ("cs_signature_r",
&sig->details.cs_signature.r_point),
GNUNET_JSON_pack_data_auto ("cs_signature_s",
&sig->details.cs_signature.s_scalar));
break;
default:
GNUNET_assert (0);
}
@ -113,13 +132,62 @@ TALER_JSON_pack_blinded_denom_sig (
switch (sig->cipher)
{
case TALER_DENOMINATION_RSA:
ps.object
= GNUNET_JSON_PACK (
ps.object = GNUNET_JSON_PACK (
GNUNET_JSON_pack_uint64 ("cipher",
TALER_DENOMINATION_RSA),
GNUNET_JSON_pack_rsa_signature ("blinded_rsa_signature",
sig->details.blinded_rsa_signature));
break;
case TALER_DENOMINATION_CS:
ps.object = GNUNET_JSON_PACK (
GNUNET_JSON_pack_uint64 ("cipher",
TALER_DENOMINATION_CS),
GNUNET_JSON_pack_uint64 ("b",
sig->details.blinded_cs_answer.b),
GNUNET_JSON_pack_data_auto ("s",
&sig->details.blinded_cs_answer.s_scalar));
break;
default:
GNUNET_assert (0);
}
return ps;
}
struct GNUNET_JSON_PackSpec
TALER_JSON_pack_blinded_planchet (
const char *name,
const struct TALER_BlindedPlanchet *blinded_planchet)
{
struct GNUNET_JSON_PackSpec ps = {
.field_name = name,
};
switch (blinded_planchet->cipher)
{
case TALER_DENOMINATION_RSA:
ps.object = GNUNET_JSON_PACK (
GNUNET_JSON_pack_uint64 ("cipher",
TALER_DENOMINATION_RSA),
GNUNET_JSON_pack_data_varsize (
"rsa_blinded_planchet",
blinded_planchet->details.rsa_blinded_planchet.blinded_msg,
blinded_planchet->details.rsa_blinded_planchet.blinded_msg_size));
break;
case TALER_DENOMINATION_CS:
ps.object = GNUNET_JSON_PACK (
GNUNET_JSON_pack_uint64 ("cipher",
TALER_DENOMINATION_CS),
GNUNET_JSON_pack_data_auto (
"cs_nonce",
&blinded_planchet->details.cs_blinded_planchet.nonce),
GNUNET_JSON_pack_data_auto (
"cs_blinded_c0",
&blinded_planchet->details.cs_blinded_planchet.c[0]),
GNUNET_JSON_pack_data_auto (
"cs_blinded_c1",
&blinded_planchet->details.cs_blinded_planchet.c[1]));
break;
default:
GNUNET_assert (0);
}

View File

@ -29,7 +29,7 @@ TALER_JSON_merchant_wire_signature_hash (const json_t *wire_s,
struct TALER_MerchantWireHash *hc)
{
const char *payto_uri;
struct TALER_WireSalt salt;
struct TALER_WireSaltP salt;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_string ("payto_uri",
&payto_uri),

View File

@ -160,7 +160,7 @@ test_contract (void)
GNUNET_assert (GNUNET_OK ==
TALER_JSON_contract_part_forget (c1,
"k2"));
json_dumpf (c1, stderr, JSON_INDENT (2));
// json_dumpf (c1, stderr, JSON_INDENT (2));
GNUNET_assert (GNUNET_OK ==
TALER_JSON_contract_hash (c1,
&h2));
@ -182,7 +182,7 @@ test_contract (void)
GNUNET_assert (GNUNET_OK ==
TALER_JSON_contract_hash (c1,
&h1));
json_dumpf (c1, stderr, JSON_INDENT (2));
// json_dumpf (c1, stderr, JSON_INDENT (2));
json_decref (c1);
{
char *s;
@ -330,6 +330,57 @@ test_contract (void)
}
static int
test_json_canon (void)
{
{
json_t *c1;
char *canon;
c1 = json_pack ("{s:s}",
"k1", "Hello\nWorld");
canon = TALER_JSON_canonicalize (c1);
GNUNET_assert (NULL != canon);
printf ("canon: '%s'\n", canon);
GNUNET_assert (0 == strcmp (canon,
"{\"k1\":\"Hello\\nWorld\"}"));
}
{
json_t *c1;
char *canon;
c1 = json_pack ("{s:s}",
"k1", "Testing “unicode” characters");
canon = TALER_JSON_canonicalize (c1);
GNUNET_assert (NULL != canon);
printf ("canon: '%s'\n", canon);
GNUNET_assert (0 == strcmp (canon,
"{\"k1\":\"Testing “unicode” characters\"}"));
}
{
json_t *c1;
char *canon;
c1 = json_pack ("{s:s}",
"k1", "low range \x05 chars");
canon = TALER_JSON_canonicalize (c1);
GNUNET_assert (NULL != canon);
printf ("canon: '%s'\n", canon);
GNUNET_assert (0 == strcmp (canon,
"{\"k1\":\"low range \\u0005 chars\"}"));
}
return 0;
}
static int
test_rfc8785 (void)
{
@ -348,7 +399,7 @@ test_rfc8785 (void)
sizeof (h1));
if (0 !=
strcmp (s,
"J678K3PW9Y3DG63Z3T7ZYR2P7CEXMVZ2SFPQMABACK9TJRYREPP82542PCJ0P7Y7FAQAMWECDX50XH1RBTWHX6SSJHH6FXRV0JCS6R8"))
"531S33T8ZRGW6548G7T67PMDNGS4Z1D8A2GMB87G3PNKYTW6KGF7Q99XVCGXBKVA2HX6PR5ENJ1PQ5ZTYMMXQB6RM7S82VP7ZG2X5G8"))
{
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Invalid reference hash: %s\n",
@ -377,6 +428,8 @@ main (int argc,
return 1;
if (0 != test_contract ())
return 2;
if (0 != test_json_canon ())
return 2;
if (0 != test_rfc8785 ())
return 2;
return 0;

View File

@ -24,6 +24,7 @@ libtalerexchange_la_SOURCES = \
exchange_api_auditor_add_denomination.c \
exchange_api_curl_defaults.c exchange_api_curl_defaults.h \
exchange_api_common.c \
exchange_api_csr.c \
exchange_api_handle.c exchange_api_handle.h \
exchange_api_deposit.c \
exchange_api_deposits_get.c \

327
src/lib/exchange_api_csr.c Normal file
View File

@ -0,0 +1,327 @@
/*
This file is part of TALER
Copyright (C) 2014-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see
<http://www.gnu.org/licenses/>
*/
/**
* @file lib/exchange_api_csr.c
* @brief Implementation of /csr requests (get R in exchange used for Clause Schnorr withdraw and refresh)
* @author Lucien Heuzeveldt
* @author Gian Demarmels
*/
#include "platform.h"
#include <jansson.h>
#include <microhttpd.h> /* just for HTTP status codes */
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_json_lib.h>
#include <gnunet/gnunet_curl_lib.h>
#include "taler_exchange_service.h"
#include "taler_json_lib.h"
#include "exchange_api_handle.h"
#include "taler_signatures.h"
#include "exchange_api_curl_defaults.h"
/**
* @brief A Clause Schnorr R Handle
*/
struct TALER_EXCHANGE_CsRHandle
{
/**
* The connection to exchange this request handle will use
*/
struct TALER_EXCHANGE_Handle *exchange;
/**
* Function to call with the result.
*/
TALER_EXCHANGE_CsRCallback cb;
/**
* Closure for @a cb.
*/
void *cb_cls;
/**
* The url for this request.
*/
char *url;
/**
* Handle for the request.
*/
struct GNUNET_CURL_Job *job;
/**
* Context for #TEH_curl_easy_post(). Keeps the data that must
* persist for Curl to make the upload.
*/
struct TALER_CURL_PostContext post_ctx;
};
/**
* We got a 200 OK response for the /reserves/$RESERVE_PUB/withdraw operation.
* Extract the coin's signature and return it to the caller. The signature we
* get from the exchange is for the blinded value. Thus, we first must
* unblind it and then should verify its validity against our coin's hash.
*
* If everything checks out, we return the unblinded signature
* to the application via the callback.
*
* @param csrh operation handle
* @param arr reply from the exchange
* @param hr http response details
* @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
*/
static enum GNUNET_GenericReturnValue
csr_ok (struct TALER_EXCHANGE_CsRHandle *csrh,
json_t *arr,
struct TALER_EXCHANGE_HttpResponse *hr)
{
unsigned int alen = json_array_size (arr);
struct TALER_ExchangeWithdrawValues alg_values[GNUNET_NZL (alen)];
struct TALER_EXCHANGE_CsRResponse csrr = {
.hr = *hr,
.details.success.alg_values_len = alen,
.details.success.alg_values = alg_values
};
for (unsigned int i = 0; i<alen; i++)
{
json_t *av = json_array_get (arr,
i);
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed (
"r_pub_0",
&alg_values[i].details.cs_values.r_pub_pair.r_pub[0],
sizeof (struct GNUNET_CRYPTO_CsRPublic)),
GNUNET_JSON_spec_fixed (
"r_pub_1",
&alg_values[i].details.cs_values.r_pub_pair.r_pub[1],
sizeof (struct GNUNET_CRYPTO_CsRPublic)),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (av,
spec,
NULL, NULL))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
}
csrh->cb (csrh->cb_cls,
&csrr);
return GNUNET_OK;
}
/**
* Function called when we're done processing the HTTP /csr request.
*
* @param cls the `struct TALER_EXCHANGE_CsRHandle`
* @param response_code HTTP response code, 0 on error
* @param response parsed JSON result, NULL on error
*/
static void
handle_csr_finished (void *cls,
long response_code,
const void *response)
{
struct TALER_EXCHANGE_CsRHandle *csrh = cls;
const json_t *j = response;
struct TALER_EXCHANGE_HttpResponse hr = {
.reply = j,
.http_status = (unsigned int) response_code
};
struct TALER_EXCHANGE_CsRResponse csrr = {
.hr = hr
};
csrh->job = NULL;
switch (response_code)
{
case 0:
csrr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
break;
case MHD_HTTP_OK:
{
json_t *arr;
arr = json_object_get (j,
"ewvs");
if ( (NULL == arr) ||
(0 == json_array_size (arr)) ||
(GNUNET_OK !=
csr_ok (csrh,
arr,
&hr)) )
{
GNUNET_break_op (0);
csrr.hr.http_status = 0;
csrr.hr.ec = TALER_EC_GENERIC_REPLY_MALFORMED;
break;
}
}
TALER_EXCHANGE_csr_cancel (csrh);
return;
case MHD_HTTP_BAD_REQUEST:
/* This should never happen, either us or the exchange is buggy
(or API version conflict); just pass JSON reply to the application */
csrr.hr.ec = TALER_JSON_get_error_code (j);
csrr.hr.hint = TALER_JSON_get_error_hint (j);
break;
case MHD_HTTP_NOT_FOUND:
/* Nothing really to verify, the exchange basically just says
that it doesn't know the /csr endpoint or denomination.
Can happen if the exchange doesn't support Clause Schnorr.
We should simply pass the JSON reply to the application. */
csrr.hr.ec = TALER_JSON_get_error_code (j);
csrr.hr.hint = TALER_JSON_get_error_hint (j);
break;
case MHD_HTTP_GONE:
/* could happen if denomination was revoked */
/* Note: one might want to check /keys for revocation
signature here, alas tricky in case our /keys
is outdated => left to clients */
csrr.hr.ec = TALER_JSON_get_error_code (j);
csrr.hr.hint = TALER_JSON_get_error_hint (j);
break;
case MHD_HTTP_INTERNAL_SERVER_ERROR:
/* Server had an internal issue; we should retry, but this API
leaves this to the application */
csrr.hr.ec = TALER_JSON_get_error_code (j);
csrr.hr.hint = TALER_JSON_get_error_hint (j);
break;
default:
/* unexpected response code */
GNUNET_break_op (0);
csrr.hr.ec = TALER_JSON_get_error_code (j);
csrr.hr.hint = TALER_JSON_get_error_hint (j);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Unexpected response code %u/%d for CS R request\n",
(unsigned int) response_code,
(int) hr.ec);
break;
}
csrh->cb (csrh->cb_cls,
&csrr);
csrh->cb = NULL;
TALER_EXCHANGE_csr_cancel (csrh);
}
struct TALER_EXCHANGE_CsRHandle *
TALER_EXCHANGE_csr (struct TALER_EXCHANGE_Handle *exchange,
unsigned int nks_len,
struct TALER_EXCHANGE_NonceKey *nks,
TALER_EXCHANGE_CsRCallback res_cb,
void *res_cb_cls)
{
struct TALER_EXCHANGE_CsRHandle *csrh;
json_t *csr_arr;
if (0 == nks_len)
{
GNUNET_break (0);
return NULL;
}
for (unsigned int i = 0; i<nks_len; i++)
if (TALER_DENOMINATION_CS != nks[i].pk->key.cipher)
{
GNUNET_break (0);
return NULL;
}
csrh = GNUNET_new (struct TALER_EXCHANGE_CsRHandle);
csrh->exchange = exchange;
csrh->cb = res_cb;
csrh->cb_cls = res_cb_cls;
csr_arr = json_array ();
GNUNET_assert (NULL != csr_arr);
for (unsigned int i = 0; i<nks_len; i++)
{
const struct TALER_EXCHANGE_NonceKey *nk = &nks[i];
json_t *csr_obj;
csr_obj = GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_varsize ("nonce",
&nk->nonce,
sizeof(struct TALER_CsNonce)),
GNUNET_JSON_pack_data_varsize ("denom_pub_hash",
&nk->pk->h_key,
sizeof(struct TALER_DenominationHash)));
GNUNET_assert (NULL != csr_obj);
GNUNET_assert (0 ==
json_array_append_new (csr_arr,
csr_obj));
}
csrh->url = TEAH_path_to_url (exchange,
"/csr");
if (NULL == csrh->url)
{
json_decref (csr_arr);
GNUNET_free (csrh);
return NULL;
}
{
CURL *eh;
struct GNUNET_CURL_Context *ctx;
json_t *req;
req = GNUNET_JSON_PACK (
GNUNET_JSON_pack_array_steal ("nks",
csr_arr));
ctx = TEAH_handle_to_context (exchange);
eh = TALER_EXCHANGE_curl_easy_get_ (csrh->url);
if ( (NULL == eh) ||
(GNUNET_OK !=
TALER_curl_easy_post (&csrh->post_ctx,
eh,
req)) )
{
GNUNET_break (0);
if (NULL != eh)
curl_easy_cleanup (eh);
json_decref (req);
GNUNET_free (csrh->url);
GNUNET_free (csrh);
return NULL;
}
json_decref (req);
csrh->job = GNUNET_CURL_job_add2 (ctx,
eh,
csrh->post_ctx.headers,
&handle_csr_finished,
csrh);
}
return csrh;
}
void
TALER_EXCHANGE_csr_cancel (struct TALER_EXCHANGE_CsRHandle *csrh)
{
if (NULL != csrh->job)
{
GNUNET_CURL_job_cancel (csrh->job);
csrh->job = NULL;
}
GNUNET_free (csrh->url);
TALER_curl_easy_post_finished (&csrh->post_ctx);
GNUNET_free (csrh);
}

View File

@ -545,7 +545,7 @@ TALER_EXCHANGE_deposit (
const struct TALER_Amount *amount,
struct GNUNET_TIME_Timestamp wire_deadline,
const char *merchant_payto_uri,
const struct TALER_WireSalt *wire_salt,
const struct TALER_WireSaltP *wire_salt,
const struct TALER_PrivateContractHash *h_contract_terms,
const json_t *extension_details,
const struct TALER_CoinSpendPublicKeyP *coin_pub,

View File

@ -94,6 +94,7 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,
struct TALER_BlindedDenominationSignature bsig;
struct TALER_DenominationPublicKey rpub;
struct TALER_CoinSpendSignatureP link_sig;
union TALER_DenominationBlindingKeyP bks;
struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_denom_pub ("denom_pub",
&rpub),
@ -104,7 +105,8 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,
GNUNET_JSON_spec_end ()
};
struct TALER_TransferSecretP secret;
struct TALER_PlanchetSecretsP fc;
struct TALER_PlanchetSecretsP ps;
struct TALER_ExchangeWithdrawValues alg_values;
/* parse reply */
if (GNUNET_OK !=
@ -118,23 +120,31 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,
TALER_link_recover_transfer_secret (trans_pub,
&lh->coin_priv,
&secret);
TALER_planchet_setup_refresh (&secret,
TALER_transfer_secret_to_planchet_secret (&secret,
coin_num,
&fc);
&ps);
// TODO: implement cipher handling
alg_values.cipher = TALER_DENOMINATION_RSA;
TALER_planchet_setup_coin_priv (&ps,
&alg_values,
coin_priv);
TALER_planchet_blinding_secret_create (&ps,
&alg_values,
&bks);
/* extract coin and signature */
if (GNUNET_OK !=
TALER_denom_sig_unblind (sig,
&bsig,
&fc.blinding_key,
&bks,
&rpub))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
*coin_priv = fc.coin_priv;
/* verify link_sig */
{
struct TALER_ExchangeWithdrawValues alg_values;
struct TALER_PlanchetDetail pd;
struct TALER_CoinPubHash c_hash;
struct TALER_CoinSpendPublicKeyP old_coin_pub;
@ -142,9 +152,13 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,
GNUNET_CRYPTO_eddsa_key_get_public (&lh->coin_priv.eddsa_priv,
&old_coin_pub.eddsa_pub);
// TODO: implement cipher handling
alg_values.cipher = TALER_DENOMINATION_RSA;
if (GNUNET_OK !=
TALER_planchet_prepare (&rpub,
&fc,
&alg_values,
&bks,
coin_priv,
&c_hash,
&pd))
{
@ -152,10 +166,9 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,
GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
GNUNET_CRYPTO_hash (pd.coin_ev,
pd.coin_ev_size,
&coin_envelope_hash.hash);
TALER_coin_ev_hash (&pd.blinded_planchet,
&pd.denom_pub_hash,
&coin_envelope_hash);
if (GNUNET_OK !=
TALER_wallet_link_verify (&pd.denom_pub_hash,
trans_pub,
@ -164,11 +177,11 @@ parse_link_coin (const struct TALER_EXCHANGE_LinkHandle *lh,
&link_sig))
{
GNUNET_break_op (0);
GNUNET_free (pd.coin_ev);
TALER_blinded_planchet_free (&pd.blinded_planchet);
GNUNET_JSON_parse_free (spec);
return GNUNET_SYSERR;
}
GNUNET_free (pd.coin_ev);
TALER_blinded_planchet_free (&pd.blinded_planchet);
}
/* clean up */

View File

@ -92,6 +92,8 @@ handle_ok (struct TALER_EXCHANGE_ManagementGetKeysHandle *gh,
&fk.master_pub),
GNUNET_JSON_spec_fixed_auto ("denom_secmod_public_key",
&fk.denom_secmod_public_key),
GNUNET_JSON_spec_fixed_auto ("denom_secmod_cs_public_key",
&fk.denom_secmod_cs_public_key),
GNUNET_JSON_spec_fixed_auto ("signkey_secmod_public_key",
&fk.signkey_secmod_public_key),
GNUNET_JSON_spec_end ()
@ -243,6 +245,26 @@ handle_ok (struct TALER_EXCHANGE_ManagementGetKeysHandle *gh,
}
}
break;
case TALER_DENOMINATION_CS:
{
struct TALER_CsPubHashP h_cs;
TALER_cs_pub_hash (&denom_key->key.details.cs_public_key,
&h_cs);
if (GNUNET_OK !=
TALER_exchange_secmod_cs_verify (&h_cs,
section_name,
denom_key->valid_from,
duration,
&fk.denom_secmod_cs_public_key,
&denom_key->denom_secmod_sig))
{
GNUNET_break_op (0);
ok = false;
break;
}
}
break;
default:
GNUNET_break_op (0);
ok = false;

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2015-2021 Taler Systems SA
Copyright (C) 2015-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@ -73,7 +73,34 @@ struct TALER_EXCHANGE_MeltHandle
/**
* Actual information about the melt operation.
*/
struct MeltData *md;
struct MeltData md;
/**
* The secret the entire melt operation is seeded from.
*/
const struct TALER_PlanchetSecretsP *ps;
/**
* Details about the characteristics of the requested melt operation.
*/
const struct TALER_EXCHANGE_RefreshData *rd;
/**
* Array of `num_fresh_coins` contributory values of
* the exchange to the melt operation.
*/
struct TALER_ExchangeWithdrawValues *alg_values;
/**
* Array of `num_fresh_coins` blinding secrets
* used for blinding the coins.
*/
union TALER_DenominationBlindingKeyP *bks;
/**
* Handle for the preflight request, or NULL.
*/
struct TALER_EXCHANGE_CsRHandle *csr;
/**
* Public key of the coin being melted.
@ -83,7 +110,7 @@ struct TALER_EXCHANGE_MeltHandle
/**
* @brief Public information about the coin's denomination key
*/
struct TALER_EXCHANGE_DenomPublicKey dki;
const struct TALER_EXCHANGE_DenomPublicKey *dki;
};
@ -106,12 +133,14 @@ verify_melt_signature_ok (struct TALER_EXCHANGE_MeltHandle *mh,
struct TALER_ExchangeSignatureP exchange_sig;
const struct TALER_EXCHANGE_Keys *key_state;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("exchange_sig", &exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub", exchange_pub),
GNUNET_JSON_spec_uint32 ("noreveal_index", noreveal_index),
GNUNET_JSON_spec_fixed_auto ("exchange_sig",
&exchange_sig),
GNUNET_JSON_spec_fixed_auto ("exchange_pub",
exchange_pub),
GNUNET_JSON_spec_uint32 ("noreveal_index",
noreveal_index),
GNUNET_JSON_spec_end ()
};
struct TALER_RefreshMeltConfirmationPS confirm;
if (GNUNET_OK !=
GNUNET_JSON_parse (json,
@ -121,7 +150,6 @@ verify_melt_signature_ok (struct TALER_EXCHANGE_MeltHandle *mh,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
/* check that exchange signing key is permitted */
key_state = TALER_EXCHANGE_get_keys (mh->exchange);
if (GNUNET_OK !=
@ -139,12 +167,15 @@ verify_melt_signature_ok (struct TALER_EXCHANGE_MeltHandle *mh,
return GNUNET_SYSERR;
}
/* verify signature by exchange */
confirm.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT);
confirm.purpose.size
= htonl (sizeof (struct TALER_RefreshMeltConfirmationPS));
confirm.rc = mh->md->rc;
confirm.noreveal_index = htonl (*noreveal_index);
/* verify signature by exchange -- FIXME: move to util! */
{
struct TALER_RefreshMeltConfirmationPS confirm = {
.purpose.purpose = htonl (TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT),
.purpose.size = htonl (sizeof (confirm)),
.rc = mh->md.rc,
.noreveal_index = htonl (*noreveal_index)
};
if (GNUNET_OK !=
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_EXCHANGE_CONFIRM_MELT,
&confirm,
@ -154,6 +185,7 @@ verify_melt_signature_ok (struct TALER_EXCHANGE_MeltHandle *mh,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
}
return GNUNET_OK;
}
@ -182,8 +214,8 @@ verify_melt_signature_denom_conflict (struct TALER_EXCHANGE_MeltHandle *mh,
history = json_object_get (json,
"history");
if (GNUNET_OK !=
TALER_EXCHANGE_verify_coin_history (&mh->dki,
mh->dki.value.currency,
TALER_EXCHANGE_verify_coin_history (mh->dki,
mh->dki->value.currency,
&mh->coin_pub,
history,
&h_denom_pub,
@ -192,7 +224,7 @@ verify_melt_signature_denom_conflict (struct TALER_EXCHANGE_MeltHandle *mh,
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
if (0 != GNUNET_memcmp (&mh->dki.h_key,
if (0 != GNUNET_memcmp (&mh->dki->h_key,
&h_denom_pub))
return GNUNET_OK; /* indeed, proof with different denomination key provided */
/* invalid proof provided */
@ -234,7 +266,7 @@ verify_melt_signature_spend_conflict (struct TALER_EXCHANGE_MeltHandle *mh,
}
/* Find out which coin was deemed problematic by the exchange */
mc = &mh->md->melted_coin;
mc = &mh->md.melted_coin;
/* verify coin history */
memset (&h_denom_pub,
0,
@ -242,7 +274,7 @@ verify_melt_signature_spend_conflict (struct TALER_EXCHANGE_MeltHandle *mh,
history = json_object_get (json,
"history");
if (GNUNET_OK !=
TALER_EXCHANGE_verify_coin_history (&mh->dki,
TALER_EXCHANGE_verify_coin_history (mh->dki,
mc->original_value.currency,
&mh->coin_pub,
history,
@ -281,7 +313,7 @@ verify_melt_signature_spend_conflict (struct TALER_EXCHANGE_MeltHandle *mh,
/* everything OK, valid proof of double-spending was provided */
return GNUNET_OK;
case TALER_EC_EXCHANGE_GENERIC_COIN_CONFLICTING_DENOMINATION_KEY:
if (0 != GNUNET_memcmp (&mh->dki.h_key,
if (0 != GNUNET_memcmp (&mh->dki->h_key,
&h_denom_pub))
return GNUNET_OK; /* indeed, proof with different denomination key provided */
/* invalid proof provided */
@ -338,6 +370,15 @@ handle_melt_finished (void *cls,
{
mh->melt_cb (mh->melt_cb_cls,
&hr,
(0 == hr.http_status)
? 0
: mh->rd->fresh_pks_len,
(0 == hr.http_status)
? NULL
: mh->alg_values,
(0 == hr.http_status)
? NULL
: mh->bks,
noreveal_index,
(0 == hr.http_status)
? NULL
@ -419,66 +460,62 @@ handle_melt_finished (void *cls,
if (NULL != mh->melt_cb)
mh->melt_cb (mh->melt_cb_cls,
&hr,
0,
NULL,
NULL,
UINT32_MAX,
NULL);
TALER_EXCHANGE_melt_cancel (mh);
}
struct TALER_EXCHANGE_MeltHandle *
TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange,
const json_t *refresh_data,
TALER_EXCHANGE_MeltCallback melt_cb,
void *melt_cb_cls)
static enum GNUNET_GenericReturnValue
start_melt (struct TALER_EXCHANGE_MeltHandle *mh)
{
const struct TALER_EXCHANGE_Keys *key_state;
const struct TALER_EXCHANGE_DenomPublicKey *dki;
json_t *melt_obj;
struct TALER_EXCHANGE_MeltHandle *mh;
CURL *eh;
struct GNUNET_CURL_Context *ctx;
struct MeltData *md;
struct TALER_CoinSpendSignatureP confirm_sig;
char arg_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2 + 32];
struct TALER_DenominationHash h_denom_pub;
struct TALER_CoinSpendPublicKeyP coin_pub;
GNUNET_assert (GNUNET_YES ==
TEAH_handle_is_ready (exchange));
md = TALER_EXCHANGE_deserialize_melt_data_ (refresh_data,
exchange->key_data.currency);
if (NULL == md)
if (GNUNET_OK !=
TALER_EXCHANGE_get_melt_data_ (mh->ps,
mh->rd,
mh->alg_values,
&mh->md))
{
GNUNET_break (0);
return NULL;
return GNUNET_SYSERR;
}
TALER_denom_pub_hash (&md->melted_coin.pub_key,
TALER_denom_pub_hash (&mh->md.melted_coin.pub_key,
&h_denom_pub);
TALER_wallet_melt_sign (&md->melted_coin.melt_amount_with_fee,
&md->melted_coin.fee_melt,
&md->rc,
TALER_wallet_melt_sign (&mh->md.melted_coin.melt_amount_with_fee,
&mh->md.melted_coin.fee_melt,
&mh->md.rc,
&h_denom_pub,
&md->melted_coin.coin_priv,
&mh->md.melted_coin.coin_priv,
&confirm_sig);
GNUNET_CRYPTO_eddsa_key_get_public (&md->melted_coin.coin_priv.eddsa_priv,
&coin_pub.eddsa_pub);
GNUNET_CRYPTO_eddsa_key_get_public (&mh->md.melted_coin.coin_priv.eddsa_priv,
&mh->coin_pub.eddsa_pub);
melt_obj = GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto ("denom_pub_hash",
&h_denom_pub),
TALER_JSON_pack_denom_sig ("denom_sig",
&md->melted_coin.sig),
&mh->md.melted_coin.sig),
GNUNET_JSON_pack_data_auto ("confirm_sig",
&confirm_sig),
TALER_JSON_pack_amount ("value_with_fee",
&md->melted_coin.melt_amount_with_fee),
&mh->md.melted_coin.melt_amount_with_fee),
GNUNET_JSON_pack_data_auto ("rc",
&md->rc));
&mh->md.rc));
{
char pub_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2];
char *end;
end = GNUNET_STRINGS_data_to_string (
&coin_pub,
&mh->coin_pub,
sizeof (struct TALER_CoinSpendPublicKeyP),
pub_str,
sizeof (pub_str));
@ -489,29 +526,19 @@ TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange,
pub_str);
}
key_state = TALER_EXCHANGE_get_keys (exchange);
dki = TALER_EXCHANGE_get_denomination_key (key_state,
&md->melted_coin.pub_key);
ctx = TEAH_handle_to_context (mh->exchange);
key_state = TALER_EXCHANGE_get_keys (mh->exchange);
mh->dki = TALER_EXCHANGE_get_denomination_key (key_state,
&mh->md.melted_coin.pub_key);
/* and now we can at last begin the actual request handling */
mh = GNUNET_new (struct TALER_EXCHANGE_MeltHandle);
mh->exchange = exchange;
mh->coin_pub = coin_pub;
mh->dki = *dki;
memset (&mh->dki.key,
0,
sizeof (mh->dki.key)); /* lifetime not warranted, so better
not copy the pointers */
mh->melt_cb = melt_cb;
mh->melt_cb_cls = melt_cb_cls;
mh->md = md;
mh->url = TEAH_path_to_url (exchange,
mh->url = TEAH_path_to_url (mh->exchange,
arg_str);
if (NULL == mh->url)
{
json_decref (melt_obj);
GNUNET_free (mh);
return NULL;
return GNUNET_SYSERR;
}
eh = TALER_EXCHANGE_curl_easy_get_ (mh->url);
if ( (NULL == eh) ||
@ -524,17 +551,156 @@ TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange,
if (NULL != eh)
curl_easy_cleanup (eh);
json_decref (melt_obj);
GNUNET_free (mh->url);
GNUNET_free (mh);
return NULL;
return GNUNET_SYSERR;
}
json_decref (melt_obj);
ctx = TEAH_handle_to_context (exchange);
mh->job = GNUNET_CURL_job_add2 (ctx,
eh,
mh->ctx.headers,
&handle_melt_finished,
mh);
return GNUNET_OK;
}
static void
fail_mh (struct TALER_EXCHANGE_MeltHandle *mh)
{
// FIXME: do return more than NULLs if
// the /csr failed!
mh->melt_cb (mh->melt_cb_cls,
NULL,
0,
NULL,
NULL,
UINT32_MAX,
NULL);
TALER_EXCHANGE_melt_cancel (mh);
}
/**
* Callbacks of this type are used to serve the result of submitting a
* CS R request to a exchange.
*
* @param cls closure with our `struct TALER_EXCHANGE_MeltHandle *`
* @param csrr response details
*/
static void
csr_cb (void *cls,
const struct TALER_EXCHANGE_CsRResponse *csrr)
{
struct TALER_EXCHANGE_MeltHandle *mh = cls;
unsigned int nks_off = 0;
for (unsigned int i = 0; i<mh->rd->fresh_pks_len; i++)
{
const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk =
&mh->rd->fresh_pks[i];
struct TALER_ExchangeWithdrawValues *wv = &mh->alg_values[i];
switch (fresh_pk->key.cipher)
{
case TALER_DENOMINATION_INVALID:
GNUNET_break (0);
fail_mh (mh);
return;
case TALER_DENOMINATION_RSA:
GNUNET_assert (TALER_DENOMINATION_RSA == wv->cipher);
break;
case TALER_DENOMINATION_CS:
GNUNET_assert (TALER_DENOMINATION_CS == wv->cipher);
*wv = csrr->details.success.alg_values[nks_off];
nks_off++;
break;
}
}
if (GNUNET_OK !=
start_melt (mh))
{
GNUNET_break (0);
fail_mh (mh);
return;
}
}
struct TALER_EXCHANGE_MeltHandle *
TALER_EXCHANGE_melt (struct TALER_EXCHANGE_Handle *exchange,
const struct TALER_PlanchetSecretsP *ps,
const struct TALER_EXCHANGE_RefreshData *rd,
TALER_EXCHANGE_MeltCallback melt_cb,
void *melt_cb_cls)
{
struct TALER_EXCHANGE_NonceKey nks[GNUNET_NZL (rd->fresh_pks_len)];
unsigned int nks_off = 0;
struct TALER_EXCHANGE_MeltHandle *mh;
if (0 == rd->fresh_pks_len)
{
GNUNET_break (0);
return NULL;
}
GNUNET_assert (GNUNET_YES ==
TEAH_handle_is_ready (exchange));
mh = GNUNET_new (struct TALER_EXCHANGE_MeltHandle);
mh->exchange = exchange;
mh->rd = rd;
mh->ps = ps;
mh->melt_cb = melt_cb;
mh->melt_cb_cls = melt_cb_cls;
mh->alg_values = GNUNET_new_array (rd->fresh_pks_len,
struct TALER_ExchangeWithdrawValues);
mh->bks = GNUNET_new_array (rd->fresh_pks_len,
union TALER_DenominationBlindingKeyP);
for (unsigned int i = 0; i<rd->fresh_pks_len; i++)
{
const struct TALER_EXCHANGE_DenomPublicKey *fresh_pk = &rd->fresh_pks[i];
struct TALER_ExchangeWithdrawValues *wv = &mh->alg_values[i];
switch (fresh_pk->key.cipher)
{
case TALER_DENOMINATION_INVALID:
GNUNET_break (0);
GNUNET_free (mh->alg_values);
GNUNET_free (mh->bks);
GNUNET_free (mh);
return NULL;
case TALER_DENOMINATION_RSA:
wv->cipher = TALER_DENOMINATION_RSA;
break;
case TALER_DENOMINATION_CS:
wv->cipher = TALER_DENOMINATION_CS;
nks[nks_off].pk = fresh_pk;
TALER_cs_refresh_nonce_derive (ps,
i,
&nks[nks_off].nonce);
nks_off++;
break;
}
}
if (0 != nks_off)
{
mh->csr = TALER_EXCHANGE_csr (exchange,
nks_off,
nks,
&csr_cb,
mh);
if (NULL == mh->csr)
{
GNUNET_break (0);
TALER_EXCHANGE_melt_cancel (mh);
return NULL;
}
return mh;
}
if (GNUNET_OK !=
start_melt (mh))
{
GNUNET_break (0);
TALER_EXCHANGE_melt_cancel (mh);
return NULL;
}
return mh;
}
@ -547,8 +713,14 @@ TALER_EXCHANGE_melt_cancel (struct TALER_EXCHANGE_MeltHandle *mh)
GNUNET_CURL_job_cancel (mh->job);
mh->job = NULL;
}
TALER_EXCHANGE_free_melt_data_ (mh->md); /* does not free 'md' itself */
GNUNET_free (mh->md);
if (NULL != mh->csr)
{
TALER_EXCHANGE_csr_cancel (mh->csr);
mh->csr = NULL;
}
TALER_EXCHANGE_free_melt_data_ (&mh->md); /* does not free 'md' itself */
GNUNET_free (mh->alg_values);
GNUNET_free (mh->bks);
GNUNET_free (mh->url);
TALER_curl_easy_post_finished (&mh->ctx);
GNUNET_free (mh);

View File

@ -284,6 +284,7 @@ struct TALER_EXCHANGE_RecoupHandle *
TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
const struct TALER_EXCHANGE_DenomPublicKey *pk,
const struct TALER_DenominationSignature *denom_sig,
const struct TALER_ExchangeWithdrawValues *exchange_vals,
const struct TALER_PlanchetSecretsP *ps,
TALER_EXCHANGE_RecoupResultCallback recoup_cb,
void *recoup_cb_cls)
@ -296,16 +297,25 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
json_t *recoup_obj;
CURL *eh;
char arg_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2 + 32];
struct TALER_CoinSpendPrivateKeyP coin_priv;
union TALER_DenominationBlindingKeyP bks;
GNUNET_assert (GNUNET_YES ==
TEAH_handle_is_ready (exchange));
GNUNET_CRYPTO_eddsa_key_get_public (&ps->coin_priv.eddsa_priv,
TALER_planchet_setup_coin_priv (ps,
exchange_vals,
&coin_priv);
TALER_planchet_blinding_secret_create (ps,
exchange_vals,
&bks);
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv.eddsa_priv,
&coin_pub.eddsa_pub);
TALER_denom_pub_hash (&pk->key,
&h_denom_pub);
TALER_wallet_recoup_sign (&h_denom_pub,
&ps->blinding_key,
&ps->coin_priv,
&bks,
&coin_priv,
&coin_sig);
recoup_obj = GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto ("denom_pub_hash",
@ -315,7 +325,7 @@ TALER_EXCHANGE_recoup (struct TALER_EXCHANGE_Handle *exchange,
GNUNET_JSON_pack_data_auto ("coin_sig",
&coin_sig),
GNUNET_JSON_pack_data_auto ("coin_blind_key_secret",
&ps->blinding_key));
&bks));
{
char pub_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2];

View File

@ -286,6 +286,7 @@ TALER_EXCHANGE_recoup_refresh (
struct TALER_EXCHANGE_Handle *exchange,
const struct TALER_EXCHANGE_DenomPublicKey *pk,
const struct TALER_DenominationSignature *denom_sig,
const struct TALER_ExchangeWithdrawValues *exchange_vals,
const struct TALER_PlanchetSecretsP *ps,
TALER_EXCHANGE_RecoupRefreshResultCallback recoup_cb,
void *recoup_cb_cls)
@ -298,16 +299,24 @@ TALER_EXCHANGE_recoup_refresh (
json_t *recoup_obj;
CURL *eh;
char arg_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2 + 32];
struct TALER_CoinSpendPrivateKeyP coin_priv;
union TALER_DenominationBlindingKeyP bks;
GNUNET_assert (GNUNET_YES ==
TEAH_handle_is_ready (exchange));
GNUNET_CRYPTO_eddsa_key_get_public (&ps->coin_priv.eddsa_priv,
TALER_planchet_setup_coin_priv (ps,
exchange_vals,
&coin_priv);
TALER_planchet_blinding_secret_create (ps,
exchange_vals,
&bks);
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv.eddsa_priv,
&coin_pub.eddsa_pub);
TALER_denom_pub_hash (&pk->key,
&h_denom_pub);
TALER_wallet_recoup_refresh_sign (&h_denom_pub,
&ps->blinding_key,
&ps->coin_priv,
&bks,
&coin_priv,
&coin_sig);
recoup_obj = GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto ("denom_pub_hash",
@ -317,7 +326,7 @@ TALER_EXCHANGE_recoup_refresh (
GNUNET_JSON_pack_data_auto ("coin_sig",
&coin_sig),
GNUNET_JSON_pack_data_auto ("coin_blind_key_secret",
&ps->blinding_key));
&bks));
{
char pub_str[sizeof (struct TALER_CoinSpendPublicKeyP) * 2];

View File

@ -23,24 +23,11 @@
#include "exchange_api_refresh_common.h"
/**
* Free all information associated with a melted coin session.
*
* @param mc melted coin to release, the pointer itself is NOT
* freed (as it is typically not allocated by itself)
*/
static void
free_melted_coin (struct MeltedCoin *mc)
{
TALER_denom_pub_free (&mc->pub_key);
TALER_denom_sig_free (&mc->sig);
}
void
TALER_EXCHANGE_free_melt_data_ (struct MeltData *md)
{
free_melted_coin (&md->melted_coin);
TALER_denom_pub_free (&md->melted_coin.pub_key);
TALER_denom_sig_free (&md->melted_coin.sig);
if (NULL != md->fresh_pks)
{
for (unsigned int i = 0; i<md->num_fresh_coins; i++)
@ -55,412 +42,142 @@ TALER_EXCHANGE_free_melt_data_ (struct MeltData *md)
}
/**
* Serialize information about a coin we are melting.
*
* @param mc information to serialize
* @return NULL on error
*/
static json_t *
serialize_melted_coin (const struct MeltedCoin *mc)
enum GNUNET_GenericReturnValue
TALER_EXCHANGE_get_melt_data_ (
const struct TALER_PlanchetSecretsP *ps,
const struct TALER_EXCHANGE_RefreshData *rd,
const struct TALER_ExchangeWithdrawValues *alg_values,
struct MeltData *md)
{
json_t *tprivs;
tprivs = json_array ();
GNUNET_assert (NULL != tprivs);
for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++)
GNUNET_assert (0 ==
json_array_append_new (
tprivs,
GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto (
"transfer_priv",
&mc->transfer_priv[i]))));
return GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto ("coin_priv",
&mc->coin_priv),
TALER_JSON_pack_denom_sig ("denom_sig",
&mc->sig),
TALER_JSON_pack_denom_pub ("denom_pub",
&mc->pub_key),
TALER_JSON_pack_amount ("melt_amount_with_fee",
&mc->melt_amount_with_fee),
TALER_JSON_pack_amount ("original_value",
&mc->original_value),
TALER_JSON_pack_amount ("melt_fee",
&mc->fee_melt),
GNUNET_JSON_pack_timestamp ("expire_deposit",
mc->expire_deposit),
GNUNET_JSON_pack_array_steal ("transfer_privs",
tprivs));
}
/**
* Deserialize information about a coin we are melting.
*
* @param[out] mc information to deserialize
* @param currency expected currency
* @param in JSON object to read data from
* @return #GNUNET_NO to report errors
*/
static enum GNUNET_GenericReturnValue
deserialize_melted_coin (struct MeltedCoin *mc,
const char *currency,
const json_t *in)
{
json_t *trans_privs;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("coin_priv",
&mc->coin_priv),
TALER_JSON_spec_denom_sig ("denom_sig",
&mc->sig),
TALER_JSON_spec_denom_pub ("denom_pub",
&mc->pub_key),
TALER_JSON_spec_amount ("melt_amount_with_fee",
currency,
&mc->melt_amount_with_fee),
TALER_JSON_spec_amount ("original_value",
currency,
&mc->original_value),
TALER_JSON_spec_amount ("melt_fee",
currency,
&mc->fee_melt),
GNUNET_JSON_spec_timestamp ("expire_deposit",
&mc->expire_deposit),
GNUNET_JSON_spec_json ("transfer_privs",
&trans_privs),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (in,
spec,
NULL, NULL))
{
GNUNET_break_op (0);
return GNUNET_NO;
}
if (TALER_CNC_KAPPA != json_array_size (trans_privs))
{
GNUNET_JSON_parse_free (spec);
GNUNET_break_op (0);
return GNUNET_NO;
}
for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++)
{
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("transfer_priv",
&mc->transfer_priv[i]),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (json_array_get (trans_privs,
i),
spec,
NULL, NULL))
{
GNUNET_break_op (0);
GNUNET_JSON_parse_free (spec);
return GNUNET_NO;
}
}
json_decref (trans_privs);
return GNUNET_OK;
}
/**
* Serialize melt data.
*
* @param md data to serialize
* @return serialized melt data
*/
static json_t *
serialize_melt_data (const struct MeltData *md)
{
json_t *fresh_coins;
fresh_coins = json_array ();
GNUNET_assert (NULL != fresh_coins);
for (int i = 0; i<md->num_fresh_coins; i++)
{
json_t *planchet_secrets;
planchet_secrets = json_array ();
GNUNET_assert (NULL != planchet_secrets);
for (unsigned int j = 0; j<TALER_CNC_KAPPA; j++)
{
json_t *ps;
ps = GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto ("ps",
&md->fresh_coins[j][i]));
GNUNET_assert (0 ==
json_array_append_new (planchet_secrets,
ps));
}
GNUNET_assert (0 ==
json_array_append_new (
fresh_coins,
GNUNET_JSON_PACK (
TALER_JSON_pack_denom_pub ("denom_pub",
&md->fresh_pks[i]),
GNUNET_JSON_pack_array_steal ("planchet_secrets",
planchet_secrets)))
);
}
return GNUNET_JSON_PACK (
GNUNET_JSON_pack_array_steal ("fresh_coins",
fresh_coins),
GNUNET_JSON_pack_object_steal ("melted_coin",
serialize_melted_coin (&md->melted_coin)),
GNUNET_JSON_pack_data_auto ("rc",
&md->rc));
}
struct MeltData *
TALER_EXCHANGE_deserialize_melt_data_ (const json_t *melt_data,
const char *currency)
{
struct MeltData *md = GNUNET_new (struct MeltData);
json_t *fresh_coins;
json_t *melted_coin;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_fixed_auto ("rc",
&md->rc),
GNUNET_JSON_spec_json ("melted_coin",
&melted_coin),
GNUNET_JSON_spec_json ("fresh_coins",
&fresh_coins),
GNUNET_JSON_spec_end ()
};
bool ok;
if (GNUNET_OK !=
GNUNET_JSON_parse (melt_data,
spec,
NULL, NULL))
{
GNUNET_break (0);
GNUNET_JSON_parse_free (spec);
GNUNET_free (md);
return NULL;
}
if (! (json_is_array (fresh_coins) &&
json_is_object (melted_coin)) )
{
GNUNET_break (0);
GNUNET_JSON_parse_free (spec);
return NULL;
}
if (GNUNET_OK !=
deserialize_melted_coin (&md->melted_coin,
currency,
melted_coin))
{
GNUNET_break (0);
GNUNET_JSON_parse_free (spec);
return NULL;
}
md->num_fresh_coins = json_array_size (fresh_coins);
md->fresh_pks = GNUNET_new_array (md->num_fresh_coins,
struct TALER_DenominationPublicKey);
for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++)
md->fresh_coins[i] = GNUNET_new_array (md->num_fresh_coins,
struct TALER_PlanchetSecretsP);
ok = true;
for (unsigned int i = 0; i<md->num_fresh_coins; i++)
{
const json_t *ji = json_array_get (fresh_coins,
i);
json_t *planchet_secrets;
struct GNUNET_JSON_Specification ispec[] = {
GNUNET_JSON_spec_json ("planchet_secrets",
&planchet_secrets),
TALER_JSON_spec_denom_pub ("denom_pub",
&md->fresh_pks[i]),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (ji,
ispec,
NULL, NULL))
{
GNUNET_break (0);
ok = false;
break;
}
if ( (! json_is_array (planchet_secrets)) ||
(TALER_CNC_KAPPA != json_array_size (planchet_secrets)) )
{
GNUNET_break (0);
ok = false;
GNUNET_JSON_parse_free (ispec);
break;
}
for (unsigned int j = 0; j<TALER_CNC_KAPPA; j++)
{
struct GNUNET_JSON_Specification jspec[] = {
GNUNET_JSON_spec_fixed_auto ("ps",
&md->fresh_coins[j][i]),
GNUNET_JSON_spec_end ()
};
if (GNUNET_OK !=
GNUNET_JSON_parse (json_array_get (planchet_secrets,
j),
jspec,
NULL, NULL))
{
GNUNET_break (0);
ok = false;
break;
}
}
json_decref (planchet_secrets);
if (! ok)
break;
}
GNUNET_JSON_parse_free (spec);
if (! ok)
{
TALER_EXCHANGE_free_melt_data_ (md);
GNUNET_free (md);
return NULL;
}
return md;
}
json_t *
TALER_EXCHANGE_refresh_prepare (
const struct TALER_CoinSpendPrivateKeyP *melt_priv,
const struct TALER_Amount *melt_amount,
const struct TALER_DenominationSignature *melt_sig,
const struct TALER_EXCHANGE_DenomPublicKey *melt_pk,
unsigned int fresh_pks_len,
const struct TALER_EXCHANGE_DenomPublicKey *fresh_pks)
{
struct MeltData md;
json_t *ret;
struct TALER_Amount total;
struct TALER_CoinSpendPublicKeyP coin_pub;
struct TALER_TransferSecretP trans_sec[TALER_CNC_KAPPA];
struct TALER_RefreshCommitmentEntry rce[TALER_CNC_KAPPA];
GNUNET_CRYPTO_eddsa_key_get_public (&melt_priv->eddsa_priv,
GNUNET_CRYPTO_eddsa_key_get_public (&rd->melt_priv.eddsa_priv,
&coin_pub.eddsa_pub);
/* build up melt data structure */
memset (&md,
memset (md,
0,
sizeof (md));
md.num_fresh_coins = fresh_pks_len;
md.melted_coin.coin_priv = *melt_priv;
md.melted_coin.melt_amount_with_fee = *melt_amount;
md.melted_coin.fee_melt = melt_pk->fee_refresh;
md.melted_coin.original_value = melt_pk->value;
md.melted_coin.expire_deposit
= melt_pk->expire_deposit;
sizeof (*md));
md->num_fresh_coins = rd->fresh_pks_len;
md->melted_coin.coin_priv = rd->melt_priv;
md->melted_coin.melt_amount_with_fee = rd->melt_amount;
md->melted_coin.fee_melt = rd->melt_pk.fee_refresh;
md->melted_coin.original_value = rd->melt_pk.value;
md->melted_coin.expire_deposit = rd->melt_pk.expire_deposit;
GNUNET_assert (GNUNET_OK ==
TALER_amount_set_zero (melt_amount->currency,
TALER_amount_set_zero (rd->melt_amount.currency,
&total));
TALER_denom_pub_deep_copy (&md.melted_coin.pub_key,
&melt_pk->key);
TALER_denom_sig_deep_copy (&md.melted_coin.sig,
melt_sig);
md.fresh_pks = GNUNET_new_array (fresh_pks_len,
TALER_denom_pub_deep_copy (&md->melted_coin.pub_key,
&rd->melt_pk.key);
TALER_denom_sig_deep_copy (&md->melted_coin.sig,
&rd->melt_sig);
md->fresh_pks = GNUNET_new_array (rd->fresh_pks_len,
struct TALER_DenominationPublicKey);
for (unsigned int i = 0; i<fresh_pks_len; i++)
for (unsigned int i = 0; i<rd->fresh_pks_len; i++)
{
TALER_denom_pub_deep_copy (&md.fresh_pks[i],
&fresh_pks[i].key);
TALER_denom_pub_deep_copy (&md->fresh_pks[i],
&rd->fresh_pks[i].key);
if ( (0 >
TALER_amount_add (&total,
&total,
&fresh_pks[i].value)) ||
&rd->fresh_pks[i].value)) ||
(0 >
TALER_amount_add (&total,
&total,
&fresh_pks[i].fee_withdraw)) )
&rd->fresh_pks[i].fee_withdraw)) )
{
GNUNET_break (0);
TALER_EXCHANGE_free_melt_data_ (&md);
return NULL;
TALER_EXCHANGE_free_melt_data_ (md);
memset (md,
0,
sizeof (*md));
return GNUNET_SYSERR;
}
}
/* verify that melt_amount is above total cost */
if (1 ==
TALER_amount_cmp (&total,
melt_amount) )
&rd->melt_amount) )
{
/* Eh, this operation is more expensive than the
@a melt_amount. This is not OK. */
GNUNET_break (0);
TALER_EXCHANGE_free_melt_data_ (&md);
return NULL;
TALER_EXCHANGE_free_melt_data_ (md);
memset (md,
0,
sizeof (*md));
return GNUNET_SYSERR;
}
/* build up coins */
for (unsigned int i = 0; i<TALER_CNC_KAPPA; i++)
{
GNUNET_CRYPTO_ecdhe_key_create (
&md.melted_coin.transfer_priv[i].ecdhe_priv);
TALER_planchet_secret_to_transfer_priv (
ps,
i,
&md->melted_coin.transfer_priv[i]);
GNUNET_CRYPTO_ecdhe_key_get_public (
&md.melted_coin.transfer_priv[i].ecdhe_priv,
&md->melted_coin.transfer_priv[i].ecdhe_priv,
&rce[i].transfer_pub.ecdhe_pub);
TALER_link_derive_transfer_secret (melt_priv,
&md.melted_coin.transfer_priv[i],
TALER_link_derive_transfer_secret (&rd->melt_priv,
&md->melted_coin.transfer_priv[i],
&trans_sec[i]);
md.fresh_coins[i] = GNUNET_new_array (fresh_pks_len,
md->fresh_coins[i] = GNUNET_new_array (rd->fresh_pks_len,
struct TALER_PlanchetSecretsP);
rce[i].new_coins = GNUNET_new_array (fresh_pks_len,
rce[i].new_coins = GNUNET_new_array (rd->fresh_pks_len,
struct TALER_RefreshCoinData);
for (unsigned int j = 0; j<fresh_pks_len; j++)
for (unsigned int j = 0; j<rd->fresh_pks_len; j++)
{
struct TALER_PlanchetSecretsP *fc = &md.fresh_coins[i][j];
struct TALER_PlanchetSecretsP *fc = &md->fresh_coins[i][j];
struct TALER_RefreshCoinData *rcd = &rce[i].new_coins[j];
struct TALER_PlanchetDetail pd;
struct TALER_CoinPubHash c_hash;
struct TALER_CoinSpendPrivateKeyP coin_priv;
union TALER_DenominationBlindingKeyP bks;
TALER_planchet_setup_refresh (&trans_sec[i],
TALER_transfer_secret_to_planchet_secret (&trans_sec[i],
j,
fc);
TALER_planchet_setup_coin_priv (fc,
&alg_values[j],
&coin_priv);
TALER_planchet_blinding_secret_create (fc,
&alg_values[j],
&bks);
if (GNUNET_OK !=
TALER_planchet_prepare (&md.fresh_pks[j],
fc,
TALER_planchet_prepare (&md->fresh_pks[j],
&alg_values[j],
&bks,
&coin_priv,
&c_hash,
&pd))
{
GNUNET_break_op (0);
TALER_EXCHANGE_free_melt_data_ (&md);
return NULL;
TALER_EXCHANGE_free_melt_data_ (md);
memset (md,
0,
sizeof (*md));
return GNUNET_SYSERR;
}
rcd->dk = &md.fresh_pks[j];
rcd->coin_ev = pd.coin_ev;
rcd->coin_ev_size = pd.coin_ev_size;
rcd->dk = &md->fresh_pks[j];
rcd->blinded_planchet = pd.blinded_planchet;
}
}
/* Compute refresh commitment */
TALER_refresh_get_commitment (&md.rc,
TALER_refresh_get_commitment (&md->rc,
TALER_CNC_KAPPA,
fresh_pks_len,
rd->fresh_pks_len,
rce,
&coin_pub,
melt_amount);
/* finally, serialize everything */
ret = serialize_melt_data (&md);
&rd->melt_amount);
for (unsigned int i = 0; i < TALER_CNC_KAPPA; i++)
{
for (unsigned int j = 0; j < fresh_pks_len; j++)
GNUNET_free (rce[i].new_coins[j].coin_ev);
for (unsigned int j = 0; j < rd->fresh_pks_len; j++)
TALER_blinded_planchet_free (&rce[i].new_coins[j].blinded_planchet);
GNUNET_free (rce[i].new_coins);
}
TALER_EXCHANGE_free_melt_data_ (&md);
return ret;
return GNUNET_OK;
}

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2015-2020 Taler Systems SA
Copyright (C) 2015-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@ -102,6 +102,12 @@ struct MeltData
*/
struct TALER_DenominationPublicKey *fresh_pks;
/**
* Array of @e num_fresh_coins with exchange contributions
* made during the refresh.
*/
struct TALER_ExchangeWithdrawValues *exchange_vals;
/**
* Arrays of @e num_fresh_coins with information about the fresh
* coins to be created, for each cut-and-choose dimension.
@ -111,15 +117,19 @@ struct MeltData
/**
* Deserialize melt data.
* Compute the melt data from the refresh data and secret.
*
* @param data json data to deserialize
* @param currency expected currency for the coins
* @return deserialized melt data, NULL on error
* @param ps secret internals of the refresh-reveal operation
* @param rd refresh data with the characteristics of the operation
* @param alg_values contributions from the exchange into the melt
* @param[out] rd where to write the derived melt data
*/
struct MeltData *
TALER_EXCHANGE_deserialize_melt_data_ (const json_t *data,
const char *currency);
enum GNUNET_GenericReturnValue
TALER_EXCHANGE_get_melt_data_ (
const struct TALER_PlanchetSecretsP *ps,
const struct TALER_EXCHANGE_RefreshData *rd,
const struct TALER_ExchangeWithdrawValues *alg_values,
struct MeltData *md);
/**

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2015-2021 Taler Systems SA
Copyright (C) 2015-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@ -73,7 +73,7 @@ struct TALER_EXCHANGE_RefreshesRevealHandle
/**
* Actual information about the melt operation.
*/
struct MeltData *md;
struct MeltData md;
/**
* The index selected by the exchange in cut-and-choose to not be revealed.
@ -95,12 +95,14 @@ struct TALER_EXCHANGE_RefreshesRevealHandle
*
* @param rrh operation handle
* @param json reply from the exchange
* @param[out] sigs array of length `num_fresh_coins`, initialized to contain RSA signatures
* @param[out] sigs array of length `num_fresh_coins`, initialized to contain the coin private keys
* @param[out] sigs array of length `num_fresh_coins`, initialized to contain signatures
* @return #GNUNET_OK on success, #GNUNET_SYSERR on errors
*/
static enum GNUNET_GenericReturnValue
refresh_reveal_ok (struct TALER_EXCHANGE_RefreshesRevealHandle *rrh,
const json_t *json,
struct TALER_CoinSpendPrivateKeyP *coin_privs,
struct TALER_DenominationSignature *sigs)
{
json_t *jsona;
@ -125,19 +127,20 @@ refresh_reveal_ok (struct TALER_EXCHANGE_RefreshesRevealHandle *rrh,
GNUNET_JSON_parse_free (outer_spec);
return GNUNET_SYSERR;
}
if (rrh->md->num_fresh_coins != json_array_size (jsona))
if (rrh->md.num_fresh_coins != json_array_size (jsona))
{
/* Number of coins generated does not match our expectation */
GNUNET_break_op (0);
GNUNET_JSON_parse_free (outer_spec);
return GNUNET_SYSERR;
}
for (unsigned int i = 0; i<rrh->md->num_fresh_coins; i++)
for (unsigned int i = 0; i<rrh->md.num_fresh_coins; i++)
{
const struct TALER_PlanchetSecretsP *fc;
struct TALER_DenominationPublicKey *pk;
json_t *jsonai;
struct TALER_BlindedDenominationSignature blind_sig;
struct TALER_ExchangeWithdrawValues alg_values;
struct TALER_CoinSpendPublicKeyP coin_pub;
struct TALER_CoinPubHash coin_hash;
struct GNUNET_JSON_Specification spec[] = {
@ -146,9 +149,10 @@ refresh_reveal_ok (struct TALER_EXCHANGE_RefreshesRevealHandle *rrh,
GNUNET_JSON_spec_end ()
};
struct TALER_FreshCoin coin;
union TALER_DenominationBlindingKeyP bks;
fc = &rrh->md->fresh_coins[rrh->noreveal_index][i];
pk = &rrh->md->fresh_pks[i];
fc = &rrh->md.fresh_coins[rrh->noreveal_index][i];
pk = &rrh->md.fresh_pks[i];
jsonai = json_array_get (jsona, i);
GNUNET_assert (NULL != jsonai);
@ -162,9 +166,17 @@ refresh_reveal_ok (struct TALER_EXCHANGE_RefreshesRevealHandle *rrh,
return GNUNET_SYSERR;
}
// TODO: implement cipher handling
alg_values.cipher = TALER_DENOMINATION_RSA;
TALER_planchet_setup_coin_priv (fc,
&alg_values,
&coin_privs[i]);
TALER_planchet_blinding_secret_create (fc,
&alg_values,
&bks);
/* needed to verify the signature, and we didn't store it earlier,
hence recomputing it here... */
GNUNET_CRYPTO_eddsa_key_get_public (&fc->coin_priv.eddsa_priv,
GNUNET_CRYPTO_eddsa_key_get_public (&coin_privs[i].eddsa_priv,
&coin_pub.eddsa_pub);
/* FIXME-Oec: Age commitment hash. */
TALER_coin_pub_hash (&coin_pub,
@ -173,8 +185,10 @@ refresh_reveal_ok (struct TALER_EXCHANGE_RefreshesRevealHandle *rrh,
if (GNUNET_OK !=
TALER_planchet_to_coin (pk,
&blind_sig,
fc,
&bks,
&coin_privs[i],
&coin_hash,
&alg_values,
&coin))
{
GNUNET_break_op (0);
@ -218,14 +232,16 @@ handle_refresh_reveal_finished (void *cls,
break;
case MHD_HTTP_OK:
{
struct TALER_DenominationSignature sigs[rrh->md->num_fresh_coins];
int ret;
struct TALER_DenominationSignature sigs[rrh->md.num_fresh_coins];
struct TALER_CoinSpendPrivateKeyP coin_privs[rrh->md.num_fresh_coins];
enum GNUNET_GenericReturnValue ret;
memset (sigs,
0,
sizeof (sigs));
ret = refresh_reveal_ok (rrh,
j,
coin_privs,
sigs);
if (GNUNET_OK != ret)
{
@ -236,12 +252,12 @@ handle_refresh_reveal_finished (void *cls,
{
rrh->reveal_cb (rrh->reveal_cb_cls,
&hr,
rrh->md->num_fresh_coins,
rrh->md->fresh_coins[rrh->noreveal_index],
rrh->md.num_fresh_coins,
coin_privs,
sigs);
rrh->reveal_cb = NULL;
}
for (unsigned int i = 0; i<rrh->md->num_fresh_coins; i++)
for (unsigned int i = 0; i<rrh->md.num_fresh_coins; i++)
TALER_denom_sig_free (&sigs[i]);
TALER_EXCHANGE_refreshes_reveal_cancel (rrh);
return;
@ -294,7 +310,10 @@ handle_refresh_reveal_finished (void *cls,
struct TALER_EXCHANGE_RefreshesRevealHandle *
TALER_EXCHANGE_refreshes_reveal (
struct TALER_EXCHANGE_Handle *exchange,
const json_t *refresh_data,
const struct TALER_PlanchetSecretsP *ps,
const struct TALER_EXCHANGE_RefreshData *rd,
unsigned int num_coins,
const struct TALER_ExchangeWithdrawValues *alg_values,
uint32_t noreveal_index,
TALER_EXCHANGE_RefreshesRevealCallback reveal_cb,
void *reveal_cb_cls)
@ -307,10 +326,12 @@ TALER_EXCHANGE_refreshes_reveal (
json_t *link_sigs;
CURL *eh;
struct GNUNET_CURL_Context *ctx;
struct MeltData *md;
struct MeltData md;
struct TALER_TransferPublicKeyP transfer_pub;
char arg_str[sizeof (struct TALER_RefreshCommitmentP) * 2 + 32];
struct TALER_TransferSecretP ts;
GNUNET_assert (num_coins == rd->fresh_pks_len);
if (noreveal_index >= TALER_CNC_KAPPA)
{
/* We check this here, as it would be really bad to below just
@ -326,9 +347,11 @@ TALER_EXCHANGE_refreshes_reveal (
GNUNET_break (0);
return NULL;
}
md = TALER_EXCHANGE_deserialize_melt_data_ (refresh_data,
exchange->key_data.currency);
if (NULL == md)
if (GNUNET_OK !=
TALER_EXCHANGE_get_melt_data_ (ps,
rd,
alg_values,
&md))
{
GNUNET_break (0);
return NULL;
@ -336,29 +359,45 @@ TALER_EXCHANGE_refreshes_reveal (
/* now transfer_pub */
GNUNET_CRYPTO_ecdhe_key_get_public (
&md->melted_coin.transfer_priv[noreveal_index].ecdhe_priv,
&md.melted_coin.transfer_priv[noreveal_index].ecdhe_priv,
&transfer_pub.ecdhe_pub);
TALER_link_recover_transfer_secret (&transfer_pub,
&rd->melt_priv,
&ts);
/* now new_denoms */
GNUNET_assert (NULL != (new_denoms_h = json_array ()));
GNUNET_assert (NULL != (coin_evs = json_array ()));
GNUNET_assert (NULL != (link_sigs = json_array ()));
for (unsigned int i = 0; i<md->num_fresh_coins; i++)
for (unsigned int i = 0; i<md.num_fresh_coins; i++)
{
struct TALER_DenominationHash denom_hash;
struct TALER_PlanchetDetail pd;
struct TALER_CoinPubHash c_hash;
struct TALER_PlanchetSecretsP ps;
union TALER_DenominationBlindingKeyP bks;
struct TALER_CoinSpendPrivateKeyP coin_priv;
TALER_denom_pub_hash (&md->fresh_pks[i],
TALER_denom_pub_hash (&md.fresh_pks[i],
&denom_hash);
GNUNET_assert (0 ==
json_array_append_new (new_denoms_h,
GNUNET_JSON_from_data_auto (
&denom_hash)));
TALER_transfer_secret_to_planchet_secret (&ts,
i,
&ps);
TALER_planchet_setup_coin_priv (&ps,
&alg_values[i],
&coin_priv);
TALER_planchet_blinding_secret_create (&ps,
&alg_values[i],
&bks);
if (GNUNET_OK !=
TALER_planchet_prepare (&md->fresh_pks[i],
&md->fresh_coins[noreveal_index][i],
TALER_planchet_prepare (&md.fresh_pks[i],
&alg_values[i],
&bks,
&coin_priv,
&c_hash,
&pd))
{
@ -366,27 +405,36 @@ TALER_EXCHANGE_refreshes_reveal (
GNUNET_break (0);
json_decref (new_denoms_h);
json_decref (coin_evs);
TALER_EXCHANGE_free_melt_data_ (&md);
return NULL;
}
GNUNET_assert (0 ==
json_array_append_new (coin_evs,
GNUNET_JSON_from_data (pd.coin_ev,
pd.coin_ev_size)));
GNUNET_assert (
0 ==
json_array_append_new (
coin_evs,
GNUNET_JSON_PACK (
TALER_JSON_pack_blinded_planchet (
NULL,
&pd.blinded_planchet))));
{
struct TALER_CoinSpendSignatureP link_sig;
struct TALER_BlindedCoinHash bch;
TALER_wallet_link_sign (&denom_hash,
TALER_coin_ev_hash (&pd.blinded_planchet,
&denom_hash,
&bch);
TALER_wallet_link_sign (
&denom_hash,
&transfer_pub,
pd.coin_ev,
pd.coin_ev_size,
&md->melted_coin.coin_priv,
&bch,
&md.melted_coin.coin_priv,
&link_sig);
GNUNET_assert (0 ==
json_array_append_new (
link_sigs,
GNUNET_JSON_from_data_auto (&link_sig)));
}
GNUNET_free (pd.coin_ev);
TALER_blinded_planchet_free (&pd.blinded_planchet);
}
/* build array of transfer private keys */
@ -402,7 +450,7 @@ TALER_EXCHANGE_refreshes_reveal (
GNUNET_assert (0 ==
json_array_append_new (transfer_privs,
GNUNET_JSON_from_data_auto (
&md->melted_coin.transfer_priv[j])));
&md.melted_coin.transfer_priv[j])));
}
/* build main JSON request */
@ -421,9 +469,8 @@ TALER_EXCHANGE_refreshes_reveal (
char pub_str[sizeof (struct TALER_RefreshCommitmentP) * 2];
char *end;
end = GNUNET_STRINGS_data_to_string (&md->rc,
sizeof (struct
TALER_RefreshCommitmentP),
end = GNUNET_STRINGS_data_to_string (&md.rc,
sizeof (md.rc),
pub_str,
sizeof (pub_str));
*end = '\0';
@ -444,6 +491,7 @@ TALER_EXCHANGE_refreshes_reveal (
if (NULL == rrh->url)
{
json_decref (reveal_obj);
TALER_EXCHANGE_free_melt_data_ (&md);
GNUNET_free (rrh);
return NULL;
}
@ -458,6 +506,7 @@ TALER_EXCHANGE_refreshes_reveal (
if (NULL != eh)
curl_easy_cleanup (eh);
json_decref (reveal_obj);
TALER_EXCHANGE_free_melt_data_ (&md);
GNUNET_free (rrh->url);
GNUNET_free (rrh);
return NULL;
@ -484,8 +533,7 @@ TALER_EXCHANGE_refreshes_reveal_cancel (
}
GNUNET_free (rrh->url);
TALER_curl_easy_post_finished (&rrh->ctx);
TALER_EXCHANGE_free_melt_data_ (rrh->md); /* does not free 'md' itself */
GNUNET_free (rrh->md);
TALER_EXCHANGE_free_melt_data_ (&rrh->md);
GNUNET_free (rrh);
}

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014-2021 Taler Systems SA
Copyright (C) 2014-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@ -59,10 +59,35 @@ struct TALER_EXCHANGE_WithdrawHandle
void *cb_cls;
/**
* Secrets of the planchet.
* Reserve private key.
*/
const struct TALER_ReservePrivateKeyP *reserve_priv;
/**
* Seed of the planchet.
*/
struct TALER_PlanchetSecretsP ps;
/**
* blinding secret
*/
union TALER_DenominationBlindingKeyP bks;
/**
* Private key of the coin we are withdrawing.
*/
struct TALER_CoinSpendPrivateKeyP priv;
/**
* Details of the planchet.
*/
struct TALER_PlanchetDetail pd;
/**
* Values of the @cipher selected
*/
struct TALER_ExchangeWithdrawValues alg_values;
/**
* Denomination key we are withdrawing.
*/
@ -73,6 +98,11 @@ struct TALER_EXCHANGE_WithdrawHandle
*/
struct TALER_CoinPubHash c_hash;
/**
* Handler for the CS R request (only used for TALER_DENOMINATION_CS denominations)
*/
struct TALER_EXCHANGE_CsRHandle *csrh;
};
@ -105,15 +135,20 @@ handle_reserve_withdraw_finished (
if (GNUNET_OK !=
TALER_planchet_to_coin (&wh->pk.key,
blind_sig,
&wh->ps,
&wh->bks,
&wh->priv,
&wh->c_hash,
&wh->alg_values,
&fc))
{
wr.hr.http_status = 0;
wr.hr.ec = TALER_EC_EXCHANGE_WITHDRAW_UNBLIND_FAILURE;
break;
}
wr.details.success.coin_priv = wh->priv;
wr.details.success.bks = wh->bks;
wr.details.success.sig = fc.sig;
wr.details.success.exchange_vals = wh->alg_values;
break;
}
case MHD_HTTP_ACCEPTED:
@ -148,23 +183,63 @@ handle_reserve_withdraw_finished (
/**
* Withdraw a coin from the exchange using a /reserve/withdraw request. Note
* that to ensure that no money is lost in case of hardware failures,
* the caller must have committed (most of) the arguments to disk
* before calling, and be ready to repeat the request with the same
* arguments in case of failures.
* Function called when stage 1 of CS withdraw is finished (request r_pub's)
*
* @param exchange the exchange handle; the exchange must be ready to operate
* @param pk kind of coin to create
* @param reserve_priv private key of the reserve to withdraw from
* @param ps secrets of the planchet
* caller must have committed this value to disk before the call (with @a pk)
* @param res_cb the callback to call when the final result for this request is available
* @param res_cb_cls closure for the above callback
* @return handle for the operation on success, NULL on error, i.e.
* if the inputs are invalid (i.e. denomination key not with this exchange).
* In this case, the callback is not called.
* @param cls
*/
static void
withdraw_cs_stage_two_callback (void *cls,
const struct TALER_EXCHANGE_CsRResponse *csrr)
{
struct TALER_EXCHANGE_WithdrawHandle *wh = cls;
struct TALER_EXCHANGE_WithdrawResponse wr = {
.hr = csrr->hr
};
wh->csrh = NULL;
GNUNET_assert (TALER_DENOMINATION_CS == wh->pk.key.cipher);
switch (csrr->hr.http_status)
{
case MHD_HTTP_OK:
if (1 != csrr->details.success.alg_values_len)
{
GNUNET_break (0);
wr.hr.http_status = 0;
break;
}
wh->alg_values = csrr->details.success.alg_values[0];
TALER_planchet_setup_coin_priv (&wh->ps,
&wh->alg_values,
&wh->priv);
TALER_planchet_blinding_secret_create (&wh->ps,
&wh->alg_values,
&wh->bks);
if (GNUNET_OK !=
TALER_planchet_prepare (&wh->pk.key,
&wh->alg_values,
&wh->bks,
&wh->priv,
&wh->c_hash,
&wh->pd))
{
GNUNET_break (0);
GNUNET_free (wh);
}
wh->wh2 = TALER_EXCHANGE_withdraw2 (wh->exchange,
&wh->pd,
wh->reserve_priv,
&handle_reserve_withdraw_finished,
wh);
return;
default:
break;
}
wh->cb (wh->cb_cls,
&wr);
TALER_EXCHANGE_withdraw_cancel (wh);
}
struct TALER_EXCHANGE_WithdrawHandle *
TALER_EXCHANGE_withdraw (
struct TALER_EXCHANGE_Handle *exchange,
@ -174,33 +249,70 @@ TALER_EXCHANGE_withdraw (
TALER_EXCHANGE_WithdrawCallback res_cb,
void *res_cb_cls)
{
struct TALER_PlanchetDetail pd;
struct TALER_EXCHANGE_WithdrawHandle *wh;
wh = GNUNET_new (struct TALER_EXCHANGE_WithdrawHandle);
wh->exchange = exchange;
wh->cb = res_cb;
wh->cb_cls = res_cb_cls;
wh->pk = *pk;
wh->reserve_priv = reserve_priv;
wh->ps = *ps;
wh->pk = *pk;
TALER_denom_pub_deep_copy (&wh->pk.key,
&pk->key);
switch (pk->key.cipher)
{
case TALER_DENOMINATION_RSA:
{
wh->alg_values.cipher = TALER_DENOMINATION_RSA;
TALER_planchet_setup_coin_priv (ps,
&wh->alg_values,
&wh->priv);
TALER_planchet_blinding_secret_create (ps,
&wh->alg_values,
&wh->bks);
if (GNUNET_OK !=
TALER_planchet_prepare (&pk->key,
ps,
&wh->alg_values,
&wh->bks,
&wh->priv,
&wh->c_hash,
&pd))
&wh->pd))
{
GNUNET_break (0);
GNUNET_free (wh);
return NULL;
}
TALER_denom_pub_deep_copy (&wh->pk.key,
&pk->key);
wh->wh2 = TALER_EXCHANGE_withdraw2 (exchange,
&pd,
reserve_priv,
&wh->pd,
wh->reserve_priv,
&handle_reserve_withdraw_finished,
wh);
GNUNET_free (pd.coin_ev);
break;
}
case TALER_DENOMINATION_CS:
{
struct TALER_EXCHANGE_NonceKey nk = {
.pk = pk,
};
wh->pd.blinded_planchet.cipher = TALER_DENOMINATION_CS;
TALER_cs_withdraw_nonce_derive (ps,
&nk.nonce);
wh->csrh = TALER_EXCHANGE_csr (exchange,
1, /* "array" length */
&nk,
&withdraw_cs_stage_two_callback,
wh);
break;
}
default:
GNUNET_break (0);
GNUNET_free (wh);
return NULL;
}
TALER_blinded_planchet_free (&wh->pd.blinded_planchet);
return wh;
}
@ -208,6 +320,11 @@ TALER_EXCHANGE_withdraw (
void
TALER_EXCHANGE_withdraw_cancel (struct TALER_EXCHANGE_WithdrawHandle *wh)
{
if (NULL != wh->csrh)
{
TALER_EXCHANGE_csr_cancel (wh->csrh);
wh->csrh = NULL;
}
if (NULL != wh->wh2)
{
TALER_EXCHANGE_withdraw2_cancel (wh->wh2);

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014-2021 Taler Systems SA
Copyright (C) 2014-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@ -152,7 +152,8 @@ reserve_withdraw_payment_required (
json_t *history;
size_t len;
struct GNUNET_JSON_Specification spec[] = {
TALER_JSON_spec_amount_any ("balance", &balance),
TALER_JSON_spec_amount_any ("balance",
&balance),
GNUNET_JSON_spec_end ()
};
@ -182,8 +183,8 @@ reserve_withdraw_payment_required (
not fit on the stack. Use "GNUNET_malloc_large" as a malicious
exchange may theoretically try to crash us by giving a history
that does not fit into our memory. */
rhistory = GNUNET_malloc_large (sizeof (struct
TALER_EXCHANGE_ReserveHistory)
rhistory = GNUNET_malloc_large (
sizeof (struct TALER_EXCHANGE_ReserveHistory)
* len);
if (NULL == rhistory)
{
@ -437,23 +438,25 @@ TALER_EXCHANGE_withdraw2 (
TALER_amount_hton (&req.amount_with_fee,
&wh->requested_amount);
TALER_coin_ev_hash (pd->coin_ev,
pd->coin_ev_size,
&req.h_coin_envelope);
if (GNUNET_OK != TALER_coin_ev_hash (&pd->blinded_planchet,
&pd->denom_pub_hash,
&req.h_coin_envelope))
{
GNUNET_break (0);
GNUNET_free (wh);
return NULL;
}
GNUNET_CRYPTO_eddsa_sign (&reserve_priv->eddsa_priv,
&req,
&reserve_sig.eddsa_signature);
}
{
json_t *withdraw_obj;
withdraw_obj = GNUNET_JSON_PACK (
json_t *withdraw_obj = GNUNET_JSON_PACK (
GNUNET_JSON_pack_data_auto ("denom_pub_hash",
&pd->denom_pub_hash),
GNUNET_JSON_pack_data_varsize ("coin_ev",
pd->coin_ev,
pd->coin_ev_size),
TALER_JSON_pack_blinded_planchet ("coin_ev",
&pd->blinded_planchet),
GNUNET_JSON_pack_data_auto ("reserve_sig",
&reserve_sig));
GNUNET_log (GNUNET_ERROR_TYPE_INFO,

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014, 2015, 2016, 2021 Taler Systems SA
Copyright (C) 2014, 2015, 2016, 2021, 2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@ -194,7 +194,9 @@ qconv_denom_pub (void *cls,
denom_pub->details.rsa_public_key,
&tbuf);
break;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
tlen = sizeof (denom_pub->details.cs_public_key);
break;
default:
GNUNET_assert (0);
}
@ -211,7 +213,11 @@ qconv_denom_pub (void *cls,
tlen);
GNUNET_free (tbuf);
break;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
memcpy (&buf[sizeof (be)],
&denom_pub->details.cs_public_key,
tlen);
break;
default:
GNUNET_assert (0);
}
@ -284,7 +290,9 @@ qconv_denom_sig (void *cls,
denom_sig->details.rsa_signature,
&tbuf);
break;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
tlen = sizeof (denom_sig->details.cs_signature);
break;
default:
GNUNET_assert (0);
}
@ -301,7 +309,11 @@ qconv_denom_sig (void *cls,
tlen);
GNUNET_free (tbuf);
break;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
memcpy (&buf[sizeof (be)],
&denom_sig->details.cs_signature,
tlen);
break;
default:
GNUNET_assert (0);
}
@ -374,7 +386,9 @@ qconv_blinded_denom_sig (void *cls,
denom_sig->details.blinded_rsa_signature,
&tbuf);
break;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
tlen = sizeof (denom_sig->details.blinded_cs_answer);
break;
default:
GNUNET_assert (0);
}
@ -391,7 +405,11 @@ qconv_blinded_denom_sig (void *cls,
tlen);
GNUNET_free (tbuf);
break;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
memcpy (&buf[sizeof (be)],
&denom_sig->details.blinded_cs_answer,
tlen);
break;
default:
GNUNET_assert (0);
}
@ -418,6 +436,97 @@ TALER_PQ_query_param_blinded_denom_sig (
}
/**
* Function called to convert input argument into SQL parameters.
*
* @param cls closure
* @param data pointer to input argument
* @param data_len number of bytes in @a data (if applicable)
* @param[out] param_values SQL data to set
* @param[out] param_lengths SQL length data to set
* @param[out] param_formats SQL format data to set
* @param param_length number of entries available in the @a param_values, @a param_lengths and @a param_formats arrays
* @param[out] scratch buffer for dynamic allocations (to be done via #GNUNET_malloc()
* @param scratch_length number of entries left in @a scratch
* @return -1 on error, number of offsets used in @a scratch otherwise
*/
static int
qconv_blinded_planchet (void *cls,
const void *data,
size_t data_len,
void *param_values[],
int param_lengths[],
int param_formats[],
unsigned int param_length,
void *scratch[],
unsigned int scratch_length)
{
const struct TALER_BlindedPlanchet *bp = data;
size_t tlen;
size_t len;
uint32_t be[2];
char *buf;
(void) cls;
(void) data_len;
GNUNET_assert (1 == param_length);
GNUNET_assert (scratch_length > 0);
GNUNET_break (NULL == cls);
be[0] = htonl ((uint32_t) bp->cipher);
be[1] = htonl (0x0100); /* magic marker: blinded */
switch (bp->cipher)
{
case TALER_DENOMINATION_RSA:
tlen = bp->details.rsa_blinded_planchet.blinded_msg_size;
break;
case TALER_DENOMINATION_CS:
tlen = sizeof (bp->details.cs_blinded_planchet);
break;
default:
GNUNET_assert (0);
}
len = tlen + sizeof (be);
buf = GNUNET_malloc (len);
memcpy (buf,
&be,
sizeof (be));
switch (bp->cipher)
{
case TALER_DENOMINATION_RSA:
memcpy (&buf[sizeof (be)],
bp->details.rsa_blinded_planchet.blinded_msg,
tlen);
break;
case TALER_DENOMINATION_CS:
memcpy (&buf[sizeof (be)],
&bp->details.cs_blinded_planchet,
tlen);
break;
default:
GNUNET_assert (0);
}
scratch[0] = buf;
param_values[0] = (void *) buf;
param_lengths[0] = len;
param_formats[0] = 1;
return 1;
}
struct GNUNET_PQ_QueryParam
TALER_PQ_query_param_blinded_planchet (
const struct TALER_BlindedPlanchet *bp)
{
struct GNUNET_PQ_QueryParam res = {
.conv = &qconv_blinded_planchet,
.data = bp,
.num_params = 1
};
return res;
}
/**
* Function called to convert input argument into SQL parameters.
*

View File

@ -425,7 +425,16 @@ extract_denom_pub (void *cls,
return GNUNET_SYSERR;
}
return GNUNET_OK;
// FIXME: add CS case!
case TALER_DENOMINATION_CS:
if (sizeof (pk->details.cs_public_key) != len)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
memcpy (&pk->details.cs_public_key,
res,
len);
return GNUNET_OK;
default:
GNUNET_break (0);
}
@ -543,7 +552,16 @@ extract_denom_sig (void *cls,
return GNUNET_SYSERR;
}
return GNUNET_OK;
// FIXME: add CS case!
case TALER_DENOMINATION_CS:
if (sizeof (sig->details.cs_signature) != len)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
memcpy (&sig->details.cs_signature,
res,
len);
return GNUNET_OK;
default:
GNUNET_break (0);
}
@ -661,7 +679,16 @@ extract_blinded_denom_sig (void *cls,
return GNUNET_SYSERR;
}
return GNUNET_OK;
// FIXME: add CS case!
case TALER_DENOMINATION_CS:
if (sizeof (sig->details.blinded_cs_answer) != len)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
memcpy (&sig->details.blinded_cs_answer,
res,
len);
return GNUNET_OK;
default:
GNUNET_break (0);
}
@ -703,4 +730,129 @@ TALER_PQ_result_spec_blinded_denom_sig (
}
/**
* Extract data from a Postgres database @a result at row @a row.
*
* @param cls closure
* @param result where to extract data from
* @param int row to extract data from
* @param fname name (or prefix) of the fields to extract from
* @param[in,out] dst_size where to store size of result, may be NULL
* @param[out] dst where to store the result
* @return
* #GNUNET_YES if all results could be extracted
* #GNUNET_SYSERR if a result was invalid (non-existing field or NULL)
*/
static enum GNUNET_GenericReturnValue
extract_blinded_planchet (void *cls,
PGresult *result,
int row,
const char *fname,
size_t *dst_size,
void *dst)
{
struct TALER_BlindedPlanchet *bp = dst;
size_t len;
const char *res;
int fnum;
uint32_t be[2];
(void) cls;
(void) dst_size;
fnum = PQfnumber (result,
fname);
if (fnum < 0)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
if (PQgetisnull (result,
row,
fnum))
return GNUNET_NO;
/* if a field is null, continue but
* remember that we now return a different result */
len = PQgetlength (result,
row,
fnum);
res = PQgetvalue (result,
row,
fnum);
if (len < sizeof (be))
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
memcpy (&be,
res,
sizeof (be));
if (0x0100 != ntohl (be[1])) /* magic marker: blinded */
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
res += sizeof (be);
len -= sizeof (be);
bp->cipher = ntohl (be[0]);
switch (bp->cipher)
{
case TALER_DENOMINATION_RSA:
bp->details.rsa_blinded_planchet.blinded_msg_size
= len;
bp->details.rsa_blinded_planchet.blinded_msg
= GNUNET_memdup (res,
len);
return GNUNET_OK;
case TALER_DENOMINATION_CS:
if (sizeof (bp->details.cs_blinded_planchet) != len)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
memcpy (&bp->details.cs_blinded_planchet,
res,
len);
return GNUNET_OK;
default:
GNUNET_break (0);
}
return GNUNET_SYSERR;
}
/**
* Function called to clean up memory allocated
* by a #GNUNET_PQ_ResultConverter.
*
* @param cls closure
* @param rd result data to clean up
*/
static void
clean_blinded_planchet (void *cls,
void *rd)
{
struct TALER_BlindedPlanchet *bp = rd;
(void) cls;
TALER_blinded_planchet_free (bp);
}
struct GNUNET_PQ_ResultSpec
TALER_PQ_result_spec_blinded_planchet (
const char *name,
struct TALER_BlindedPlanchet *bp)
{
struct GNUNET_PQ_ResultSpec res = {
.conv = &extract_blinded_planchet,
.cleaner = &clean_blinded_planchet,
.dst = (void *) bp,
.fname = name
};
return res;
}
/* end of pq_result_helper.c */

View File

@ -1,13 +1,16 @@
test_auditor_api_version
test_auditor_api_version_cs
test_auditor_api_version_rsa
test_bank_api_with_fakebank
test_bank_api_with_fakebank_twisted
test_bank_api_with_pybank
test_bank_api_with_pybank_twisted
test_taler_exchange_aggregator-postgres
test_taler_exchange_wirewatch-postgres
test_exchange_api_revocation
test_exchange_api_revocation_cs
test_exchange_api_revocation_rsa
report*
test_exchange_management_api
test_exchange_management_api_cs
test_exchange_management_api_rsa
test_exchange_api_home/.local/share/taler/crypto-eddsa/
test_exchange_api_home/.local/share/taler/crypto-rsa/
test_exchange_api_home/.local/share/taler/exchange/offline-keys/secm_tofus.priv
@ -24,12 +27,17 @@ test_taler_exchange_httpd_home/.local/share/taler/taler-exchange-secmod-eddsa/
test_taler_exchange_httpd_home/.local/share/taler/taler-exchange-secmod-rsa/
test_exchange_api_keys_cherry_picking_home/.local/share/taler/crypto-rsa/
test_exchange_api_home/.local/share/taler/exchange-offline/secm_tofus.pub
test_exchange_api_home/.local/share/taler/exchange-secmod-cs/
test_exchange_api_home/.local/share/taler/exchange-secmod-eddsa/
test_exchange_api_home/.local/share/taler/exchange-secmod-rsa/
test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange-offline/secm_tofus.pub
test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange-secmod-cs/
test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange-secmod-eddsa/
test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange-secmod-rsa/
test_taler_exchange_httpd_home/.local/share/taler/exchange-offline/secm_tofus.pub
test_taler_exchange_httpd_home/.local/share/taler/exchange-secmod-cs/
test_taler_exchange_httpd_home/.local/share/taler/exchange-secmod-eddsa/
test_taler_exchange_httpd_home/.local/share/taler/exchange-secmod-rsa/
test_kyc_api
test_helper_cs_home/
test_helper_rsa_home/

View File

@ -114,16 +114,23 @@ AM_TESTS_ENVIRONMENT=export TALER_PREFIX=$${TALER_PREFIX:-@libdir@};export PATH=
.NOTPARALLEL:
check_PROGRAMS = \
test_auditor_api \
test_auditor_api_version \
test_auditor_api_cs \
test_auditor_api_rsa \
test_auditor_api_version_rsa \
test_auditor_api_version_cs \
test_bank_api_with_fakebank \
test_bank_api_with_pybank \
test_bank_api_with_nexus \
test_exchange_api \
test_exchange_api_keys_cherry_picking \
test_exchange_api_revocation \
test_exchange_api_overlapping_keys_bug \
test_exchange_management_api \
test_exchange_api_cs \
test_exchange_api_rsa \
test_exchange_api_keys_cherry_picking_cs \
test_exchange_api_keys_cherry_picking_rsa \
test_exchange_api_revocation_cs \
test_exchange_api_revocation_rsa \
test_exchange_api_overlapping_keys_bug_cs \
test_exchange_api_overlapping_keys_bug_rsa \
test_exchange_management_api_cs \
test_exchange_management_api_rsa \
test_kyc_api \
test_taler_exchange_aggregator-postgres \
test_taler_exchange_wirewatch-postgres
@ -139,9 +146,9 @@ endif
TESTS = \
$(check_PROGRAMS)
test_auditor_api_SOURCES = \
test_auditor_api_cs_SOURCES = \
test_auditor_api.c
test_auditor_api_LDADD = \
test_auditor_api_cs_LDADD = \
$(top_builddir)/src/lib/libtalerauditor.la \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerexchange.la \
@ -150,19 +157,51 @@ test_auditor_api_LDADD = \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
-lgnunettesting \
-lgnunetcurl \
-lgnunetutil \
-ljansson \
$(XLIB)
test_auditor_api_rsa_SOURCES = \
test_auditor_api.c
test_auditor_api_rsa_LDADD = \
$(top_builddir)/src/lib/libtalerauditor.la \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerexchange.la \
$(LIBGCRYPT_LIBS) \
$(top_builddir)/src/bank-lib/libtalerfakebank.la \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
-lgnunettesting \
-lgnunetcurl \
-lgnunetutil \
-ljansson \
$(XLIB)
test_auditor_api_version_SOURCES = \
test_auditor_api_version_cs_SOURCES = \
test_auditor_api_version.c
test_auditor_api_version_LDADD = \
test_auditor_api_version_cs_LDADD = \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerauditor.la \
$(LIBGCRYPT_LIBS) \
$(top_builddir)/src/util/libtalerutil.la \
-lgnunettesting \
-lgnunetcurl \
-lgnunetutil \
-ljansson \
$(XLIB)
test_auditor_api_version_rsa_SOURCES = \
test_auditor_api_version.c
test_auditor_api_version_rsa_LDADD = \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerauditor.la \
$(LIBGCRYPT_LIBS) \
$(top_builddir)/src/util/libtalerutil.la \
-lgnunettesting \
-lgnunetcurl \
-lgnunetutil \
-ljansson \
@ -195,9 +234,9 @@ test_bank_api_with_pybank_LDADD = \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(XLIB)
test_exchange_api_SOURCES = \
test_exchange_api_cs_SOURCES = \
test_exchange_api.c
test_exchange_api_LDADD = \
test_exchange_api_cs_LDADD = \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerexchange.la \
$(LIBGCRYPT_LIBS) \
@ -205,23 +244,15 @@ test_exchange_api_LDADD = \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
-lgnunettesting \
-lgnunetcurl \
-lgnunetutil \
-ljansson \
$(XLIB)
test_exchange_management_api_SOURCES = \
test_exchange_management_api.c
test_exchange_management_api_LDADD = \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerexchange.la \
$(top_builddir)/src/util/libtalerutil.la \
-lgnunetutil \
$(XLIB)
test_exchange_api_revocation_SOURCES = \
test_exchange_api_revocation.c
test_exchange_api_revocation_LDADD = \
test_exchange_api_rsa_SOURCES = \
test_exchange_api.c
test_exchange_api_rsa_LDADD = \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerexchange.la \
$(LIBGCRYPT_LIBS) \
@ -229,39 +260,126 @@ test_exchange_api_revocation_LDADD = \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
-lgnunettesting \
-lgnunetcurl \
-lgnunetutil \
-ljansson \
$(XLIB)
test_exchange_api_keys_cherry_picking_SOURCES = \
test_exchange_api_keys_cherry_picking_cs_SOURCES = \
test_exchange_api_keys_cherry_picking.c
test_exchange_api_keys_cherry_picking_LDADD = \
test_exchange_api_keys_cherry_picking_cs_LDADD = \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerexchange.la \
$(LIBGCRYPT_LIBS) \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
$(top_builddir)/src/bank-lib/libtalerbank.la \
-lgnunettesting \
-lgnunetcurl \
-lgnunetutil \
-ljansson \
$(XLIB)
test_exchange_api_overlapping_keys_bug_SOURCES = \
test_exchange_api_overlapping_keys_bug.c
test_exchange_api_overlapping_keys_bug_LDADD = \
test_exchange_api_keys_cherry_picking_rsa_SOURCES = \
test_exchange_api_keys_cherry_picking.c
test_exchange_api_keys_cherry_picking_rsa_LDADD = \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerexchange.la \
$(LIBGCRYPT_LIBS) \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
$(top_builddir)/src/bank-lib/libtalerbank.la \
-lgnunettesting \
-lgnunetcurl \
-lgnunetutil \
-ljansson \
$(XLIB)
test_exchange_api_revocation_cs_SOURCES = \
test_exchange_api_revocation.c
test_exchange_api_revocation_cs_LDADD = \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerexchange.la \
$(LIBGCRYPT_LIBS) \
$(top_builddir)/src/bank-lib/libtalerfakebank.la \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
-lgnunettesting \
-lgnunetcurl \
-lgnunetutil \
-ljansson \
$(XLIB)
test_exchange_api_revocation_rsa_SOURCES = \
test_exchange_api_revocation.c
test_exchange_api_revocation_rsa_LDADD = \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerexchange.la \
$(LIBGCRYPT_LIBS) \
$(top_builddir)/src/bank-lib/libtalerfakebank.la \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
-lgnunettesting \
-lgnunetcurl \
-lgnunetutil \
-ljansson \
$(XLIB)
test_exchange_api_overlapping_keys_bug_cs_SOURCES = \
test_exchange_api_overlapping_keys_bug.c
test_exchange_api_overlapping_keys_bug_cs_LDADD = \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerexchange.la \
$(LIBGCRYPT_LIBS) \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
$(top_builddir)/src/bank-lib/libtalerbank.la \
-lgnunettesting \
-lgnunetcurl \
-lgnunetutil \
-ljansson \
$(XLIB)
test_exchange_api_overlapping_keys_bug_rsa_SOURCES = \
test_exchange_api_overlapping_keys_bug.c
test_exchange_api_overlapping_keys_bug_rsa_LDADD = \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerexchange.la \
$(LIBGCRYPT_LIBS) \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
$(top_builddir)/src/bank-lib/libtalerbank.la \
-lgnunettesting \
-lgnunetcurl \
-lgnunetutil \
-ljansson \
$(XLIB)
test_exchange_management_api_cs_SOURCES = \
test_exchange_management_api.c
test_exchange_management_api_cs_LDADD = \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerexchange.la \
$(top_builddir)/src/util/libtalerutil.la \
-lgnunettesting \
-lgnunetutil \
$(XLIB)
test_exchange_management_api_rsa_SOURCES = \
test_exchange_management_api.c
test_exchange_management_api_rsa_LDADD = \
libtalertesting.la \
$(top_builddir)/src/lib/libtalerexchange.la \
$(top_builddir)/src/util/libtalerutil.la \
-lgnunettesting \
-lgnunetutil \
$(XLIB)
test_taler_exchange_aggregator_postgres_SOURCES = \
test_taler_exchange_aggregator.c
test_taler_exchange_aggregator_postgres_LDADD = \
@ -306,6 +424,7 @@ test_exchange_api_twisted_LDADD = \
$(top_builddir)/src/bank-lib/libtalerbank.la \
$(top_builddir)/src/json/libtalerjson.la \
$(top_builddir)/src/util/libtalerutil.la \
-lgnunettesting \
-lgnunetjson \
-lgnunetcurl \
-lgnunetutil \
@ -321,6 +440,7 @@ test_bank_api_with_fakebank_twisted_LDADD = \
$(top_builddir)/src/lib/libtalerexchange.la \
$(top_builddir)/src/json/libtalerjson.la \
libtalertwistertesting.la \
-lgnunettesting \
-lgnunetjson \
-lgnunetcurl \
-lgnunetutil \
@ -336,6 +456,7 @@ test_bank_api_with_pybank_twisted_LDADD = \
$(top_builddir)/src/lib/libtalerexchange.la \
$(top_builddir)/src/json/libtalerjson.la \
libtalertwistertesting.la \
-lgnunettesting \
-lgnunetjson \
-lgnunetcurl \
-lgnunetutil \
@ -363,7 +484,8 @@ test_kyc_api_LDADD = \
EXTRA_DIST = \
test_auditor_api.conf \
test_auditor_api_expire_reserve_now.conf \
test_auditor_api_expire_reserve_now-cs.conf \
test_auditor_api_expire_reserve_now-rsa.conf \
test_bank_api_fakebank.conf \
test_bank_api_fakebank_twisted.conf \
test_bank_api_pybank.conf \
@ -376,9 +498,11 @@ EXTRA_DIST = \
test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange-offline/master.priv \
test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/offline-keys/master.priv \
test_exchange_api_keys_cherry_picking_home/.local/share/taler/exchange/wirefees/x-taler-bank.fee \
test_exchange_api.conf \
test_exchange_api-cs.conf \
test_exchange_api-rsa.conf \
test_exchange_api_twisted.conf \
test_exchange_api_keys_cherry_picking.conf \
test_exchange_api_keys_cherry_picking-cs.conf \
test_exchange_api_keys_cherry_picking-rsa.conf \
test_exchange_api_expire_reserve_now.conf \
test_taler_exchange_httpd_home/.config/taler/account-1.json \
test_taler_exchange_httpd_home/.local/share/taler/exchange-offline/master.priv \

View File

@ -92,4 +92,5 @@ fee_withdraw = EUR:0.00
fee_deposit = EUR:0.00
fee_refresh = EUR:0.01
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024

View File

@ -81,4 +81,5 @@ fee_withdraw = EUR:0.00
fee_deposit = EUR:0.00
fee_refresh = EUR:0.01
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024

View File

@ -0,0 +1,140 @@
# This file is in the public domain.
#
[PATHS]
# Persistent data storage for the testcase
TALER_TEST_HOME = test_exchange_api_home/
TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/
[taler-exchange-secmod-cs]
# Reduce from 1 year to speed up test
LOOKAHEAD_SIGN = 24 days
[taler-exchange-secmod-eddsa]
# Reduce from 1 year to speed up test
LOOKAHEAD_SIGN = 24 days
# Reduce from 12 weeks to ensure we have multiple
DURATION = 14 days
[taler]
# Currency supported by the exchange (can only be one)
CURRENCY = EUR
CURRENCY_ROUND_UNIT = EUR:0.01
[auditor]
BASE_URL = "http://localhost:8083/"
# HTTP port the auditor listens to
PORT = 8083
TINY_AMOUNT = EUR:0.01
[exchange]
# HTTP port the exchange listens to
PORT = 8081
# Master public key used to sign the exchange's various keys
MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
# How to access our database
DB = postgres
# Base URL of the exchange. Must be set to a URL where the
# exchange (or the twister) is actually listening.
BASE_URL = "http://localhost:8081/"
[exchangedb-postgres]
CONFIG = "postgres:///talercheck"
[auditordb-postgres]
CONFIG = "postgres:///talercheck"
# Sections starting with "exchange-account-" configure the bank accounts
# of the exchange. The "URL" specifies the account in
# payto://-format.
[exchange-account-1]
# What is the URL of our account?
PAYTO_URI = "payto://x-taler-bank/localhost/42"
[exchange-accountcredentials-1]
WIRE_GATEWAY_URL = "http://localhost:8082/42/"
[bank]
HTTP_PORT = 8082
# ENABLE_CREDIT = YES
[exchange-account-2]
# What is the bank account (with the "Taler Bank" demo system)?
PAYTO_URI = "payto://x-taler-bank/localhost/2"
ENABLE_DEBIT = YES
ENABLE_CREDIT = YES
# Authentication information for basic authentication
[exchange-accountcredentials-2]
WIRE_GATEWAY_URL = "http://localhost:8082/2/"
WIRE_GATEWAY_AUTH_METHOD = "basic"
USERNAME = user
PASSWORD = pass
# Sections starting with "coin_" specify which denominations
# the exchange should support (and their respective fee structure)
[coin_eur_ct_1]
value = EUR:0.01
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.00
fee_deposit = EUR:0.00
fee_refresh = EUR:0.01
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_ct_10]
value = EUR:0.10
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_1]
value = EUR:1
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_5]
value = EUR:5
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_10]
value = EUR:10
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS

View File

@ -93,6 +93,7 @@ fee_withdraw = EUR:0.00
fee_deposit = EUR:0.00
fee_refresh = EUR:0.01
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_eur_ct_10]
@ -104,6 +105,7 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_eur_1]
@ -115,6 +117,7 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_eur_5]
@ -126,6 +129,7 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_eur_10]
@ -137,4 +141,5 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024

View File

@ -29,6 +29,7 @@
#include "taler_auditor_service.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_testing_lib.h>
#include <microhttpd.h>
#include "taler_bank_service.h"
#include "taler_fakebank_lib.h"
@ -39,10 +40,9 @@
* Configuration file we use. One (big) configuration is used
* for the various components for this test.
*/
#define CONFIG_FILE "test_auditor_api.conf"
static char *config_file;
#define CONFIG_FILE_EXPIRE_RESERVE_NOW \
"test_auditor_api_expire_reserve_now.conf"
static char *config_file_expire_reserve_now;
/**
* Exchange configuration data.
@ -61,7 +61,7 @@ static struct TALER_TESTING_BankConfiguration bc;
* @param label label to use for the command.
*/
#define CMD_EXEC_WIREWATCH(label) \
TALER_TESTING_cmd_exec_wirewatch (label, CONFIG_FILE)
TALER_TESTING_cmd_exec_wirewatch (label, config_file)
/**
* Execute the taler-exchange-aggregator, closer and transfer commands with
@ -71,8 +71,8 @@ static struct TALER_TESTING_BankConfiguration bc;
*/
#define CMD_EXEC_AGGREGATOR(label) \
TALER_TESTING_cmd_sleep (label "-sleep", 1), \
TALER_TESTING_cmd_exec_aggregator (label, CONFIG_FILE), \
TALER_TESTING_cmd_exec_transfer (label, CONFIG_FILE)
TALER_TESTING_cmd_exec_aggregator (label, config_file), \
TALER_TESTING_cmd_exec_transfer (label, config_file)
/**
* Run wire transfer of funds from some user's account to the
@ -92,7 +92,7 @@ static struct TALER_TESTING_BankConfiguration bc;
* @param label label to use for the command.
*/
#define CMD_RUN_AUDITOR(label) \
TALER_TESTING_cmd_exec_auditor (label, CONFIG_FILE)
TALER_TESTING_cmd_exec_auditor (label, config_file)
/**
@ -184,7 +184,7 @@ run (void *cls,
/**
* Melt the rest of the coin's value (EUR:4.00 = 3x EUR:1.03 + 7x
* EUR:0.13)
*/
*/
TALER_TESTING_cmd_melt_double ("refresh-melt-1",
"refresh-withdraw-coin-1",
MHD_HTTP_OK,
@ -406,7 +406,7 @@ run (void *cls,
TALER_TESTING_cmd_revoke ("revoke-1",
MHD_HTTP_OK,
"recoup-withdraw-coin-1",
CONFIG_FILE),
config_file),
TALER_TESTING_cmd_recoup ("recoup-1",
MHD_HTTP_OK,
"recoup-withdraw-coin-1",
@ -426,9 +426,9 @@ run (void *cls,
CMD_TRANSFER_TO_EXCHANGE ("short-lived-reserve",
"EUR:5.01"),
TALER_TESTING_cmd_exec_wirewatch ("short-lived-aggregation",
CONFIG_FILE_EXPIRE_RESERVE_NOW),
config_file_expire_reserve_now),
TALER_TESTING_cmd_exec_aggregator ("close-reserves",
CONFIG_FILE_EXPIRE_RESERVE_NOW),
config_file_expire_reserve_now),
/**
* Fill reserve with EUR:2.02, as withdraw fee is 1 ct per
* config, then withdraw two coin, partially spend one, and
@ -466,7 +466,7 @@ run (void *cls,
TALER_TESTING_cmd_revoke ("revoke-2",
MHD_HTTP_OK,
"recoup-withdraw-coin-2a",
CONFIG_FILE),
config_file),
TALER_TESTING_cmd_recoup ("recoup-2",
MHD_HTTP_OK,
"recoup-withdraw-coin-2a",
@ -631,7 +631,7 @@ run (void *cls,
struct TALER_TESTING_Command commands[] = {
TALER_TESTING_cmd_exec_offline_sign_fees ("offline-sign-fees",
CONFIG_FILE,
config_file,
"EUR:0.01",
"EUR:0.01"),
TALER_TESTING_cmd_auditor_add ("add-auditor-OK",
@ -642,11 +642,11 @@ run (void *cls,
MHD_HTTP_NO_CONTENT,
false),
TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys",
CONFIG_FILE),
config_file),
TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
2),
TALER_TESTING_cmd_exec_auditor_offline ("auditor-offline",
CONFIG_FILE),
config_file),
CMD_RUN_AUDITOR ("virgin-auditor"),
TALER_TESTING_cmd_exchanges_with_url ("check-exchange",
MHD_HTTP_OK,
@ -682,25 +682,35 @@ int
main (int argc,
char *const *argv)
{
const char *cipher;
(void) argc;
(void) argv;
/* These environment variables get in the way... */
unsetenv ("XDG_DATA_HOME");
unsetenv ("XDG_CONFIG_HOME");
GNUNET_log_setup ("test-auditor-api",
GNUNET_log_setup (argv[0],
"INFO",
NULL);
cipher = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
GNUNET_assert (NULL != cipher);
GNUNET_asprintf (&config_file,
"test_auditor_api-%s.conf",
cipher);
GNUNET_asprintf (&config_file_expire_reserve_now,
"test_auditor_api_expire_reserve_now-%s.conf",
cipher);
/* Check fakebank port is available and get configuration data. */
if (GNUNET_OK !=
TALER_TESTING_prepare_fakebank (CONFIG_FILE,
TALER_TESTING_prepare_fakebank (config_file,
"exchange-account-2",
&bc))
return 77;
TALER_TESTING_cleanup_files (CONFIG_FILE);
TALER_TESTING_cleanup_files (config_file);
/* @helpers. Run keyup, create tables, ... Note: it
* fetches the port number from config in order to see
* if it's available. */
switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
switch (TALER_TESTING_prepare_exchange (config_file,
GNUNET_YES,
&ec))
{
@ -717,7 +727,7 @@ main (int argc,
*/
TALER_TESTING_auditor_setup (&run,
NULL,
CONFIG_FILE))
config_file))
return 1;
break;
default:

View File

@ -1,4 +1,4 @@
@INLINE@ test_auditor_api.conf
@INLINE@ test_auditor_api-cs.conf
[exchangedb]
IDLE_RESERVE_EXPIRATION_TIME = 0 s

View File

@ -0,0 +1,4 @@
@INLINE@ test_auditor_api-rsa.conf
[exchangedb]
IDLE_RESERVE_EXPIRATION_TIME = 0 s

View File

@ -0,0 +1,201 @@
# This file is in the public domain.
#
[PATHS]
# Persistent data storage for the testcase
TALER_TEST_HOME = test_exchange_api_home/
TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/
[taler-exchange-secmod-rsa]
# Reduce from 1 year to speed up test
LOOKAHEAD_SIGN = 24 days
[taler-exchange-secmod-eddsa]
# Reduce from 1 year to speed up test
LOOKAHEAD_SIGN = 24 days
# Reduce from 12 weeks to ensure we have multiple
DURATION = 14 days
[taler]
# Currency supported by the exchange (can only be one)
CURRENCY = EUR
CURRENCY_ROUND_UNIT = EUR:0.01
[auditor]
BASE_URL = "http://localhost:8083/"
# HTTP port the auditor listens to
PORT = 8083
[exchange]
TERMS_ETAG = 0
PRIVACY_ETAG = 0
# HTTP port the exchange listens to
PORT = 8081
# Master public key used to sign the exchange's various keys
MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
# How to access our database
DB = postgres
# Base URL of the exchange. Must be set to a URL where the
# exchange (or the twister) is actually listening.
BASE_URL = "http://localhost:8081/"
[exchangedb-postgres]
CONFIG = "postgres:///talercheck"
[auditordb-postgres]
CONFIG = "postgres:///talercheck"
# Sections starting with "exchange-account-" configure the bank accounts
# of the exchange. The "URL" specifies the account in
# payto://-format.
[exchange-account-1]
# What is the URL of our account?
PAYTO_URI = "payto://x-taler-bank/localhost/42"
# ENABLE_CREDIT = YES
[exchange-accountcredentials-1]
WIRE_GATEWAY_URL = "http://localhost:9081/42/"
[exchange-account-2]
# What is the bank account (with the "Taler Bank" demo system)?
PAYTO_URI = "payto://x-taler-bank/localhost/2"
ENABLE_DEBIT = YES
ENABLE_CREDIT = YES
[exchange-accountcredentials-2]
WIRE_GATEWAY_AUTH_METHOD = basic
USERNAME = Exchange
PASSWORD = x
WIRE_GATEWAY_URL = "http://localhost:9081/2/"
[bank]
HTTP_PORT = 9081
# Enabled extensions
[exchange-extension-age_restriction]
ENABLED = YES
# default age groups:
#AGE_GROUPS = "8:10:12:14:16:18:21"
# Sections starting with "coin_" specify which denominations
# the exchange should support (and their respective fee structure)
[coin_eur_ct_1]
value = EUR:0.01
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.00
fee_deposit = EUR:0.00
fee_refresh = EUR:0.01
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_ct_10]
value = EUR:0.10
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_1]
value = EUR:1
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_5]
value = EUR:5
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_10]
value = EUR:10
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_ct_1_age_restricted]
value = EUR:0.01
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.00
fee_deposit = EUR:0.00
fee_refresh = EUR:0.01
fee_refund = EUR:0.01
age_restricted = true
CIPHER = CS
[coin_eur_ct_10_age_restricted]
value = EUR:0.10
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
age_restricted = true
CIPHER = CS
[coin_eur_1_age_restricted]
value = EUR:1
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
age_restricted = true
CIPHER = CS
[coin_eur_5_age_restricted]
value = EUR:5
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
age_restricted = true
CIPHER = CS
[coin_eur_10_age_restricted]
value = EUR:10
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
age_restricted = true
CIPHER = CS

View File

@ -94,6 +94,7 @@ fee_withdraw = EUR:0.00
fee_deposit = EUR:0.00
fee_refresh = EUR:0.01
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_eur_ct_10]
@ -105,6 +106,7 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_eur_1]
@ -116,6 +118,7 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_eur_5]
@ -127,6 +130,7 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_eur_10]
@ -138,6 +142,7 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_eur_ct_1_age_restricted]
@ -151,6 +156,7 @@ fee_refresh = EUR:0.01
fee_refund = EUR:0.01
rsa_keysize = 1024
age_restricted = true
CIPHER = RSA
[coin_eur_ct_10_age_restricted]
value = EUR:0.10
@ -163,6 +169,7 @@ fee_refresh = EUR:0.03
fee_refund = EUR:0.01
rsa_keysize = 1024
age_restricted = true
CIPHER = RSA
[coin_eur_1_age_restricted]
value = EUR:1
@ -175,6 +182,7 @@ fee_refresh = EUR:0.03
fee_refund = EUR:0.01
rsa_keysize = 1024
age_restricted = true
CIPHER = RSA
[coin_eur_5_age_restricted]
value = EUR:5
@ -187,6 +195,7 @@ fee_refresh = EUR:0.03
fee_refund = EUR:0.01
rsa_keysize = 1024
age_restricted = true
CIPHER = RSA
[coin_eur_10_age_restricted]
value = EUR:10
@ -199,3 +208,4 @@ fee_refresh = EUR:0.03
fee_refund = EUR:0.01
rsa_keysize = 1024
age_restricted = true
CIPHER = RSA

View File

@ -29,6 +29,7 @@
#include "taler_exchange_service.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_testing_lib.h>
#include <microhttpd.h>
#include "taler_bank_service.h"
#include "taler_fakebank_lib.h"
@ -38,10 +39,9 @@
* Configuration file we use. One (big) configuration is used
* for the various components for this test.
*/
#define CONFIG_FILE "test_exchange_api.conf"
static char *config_file;
#define CONFIG_FILE_EXPIRE_RESERVE_NOW \
"test_exchange_api_expire_reserve_now.conf"
static char *config_file_expire_reserve_now;
/**
@ -62,7 +62,7 @@ static struct TALER_TESTING_BankConfiguration bc;
* @param label label to use for the command.
*/
#define CMD_EXEC_WIREWATCH(label) \
TALER_TESTING_cmd_exec_wirewatch (label, CONFIG_FILE)
TALER_TESTING_cmd_exec_wirewatch (label, config_file)
/**
* Execute the taler-exchange-aggregator, closer and transfer commands with
@ -71,8 +71,8 @@ static struct TALER_TESTING_BankConfiguration bc;
* @param label label to use for the command.
*/
#define CMD_EXEC_AGGREGATOR(label) \
TALER_TESTING_cmd_exec_aggregator (label "-aggregator", CONFIG_FILE), \
TALER_TESTING_cmd_exec_transfer (label "-transfer", CONFIG_FILE)
TALER_TESTING_cmd_exec_aggregator (label "-aggregator", config_file), \
TALER_TESTING_cmd_exec_transfer (label "-transfer", config_file)
/**
@ -406,7 +406,6 @@ run (void *cls,
TALER_TESTING_cmd_end ()
};
/**
* This block checks whether a wire deadline
* very far in the future does NOT get aggregated now.
@ -680,7 +679,7 @@ run (void *cls,
TALER_TESTING_cmd_revoke ("revoke-0-EUR:5",
MHD_HTTP_OK,
"recoup-withdraw-coin-1",
CONFIG_FILE),
config_file),
/* Recoup coin to reserve */
TALER_TESTING_cmd_recoup ("recoup-1",
MHD_HTTP_OK,
@ -780,14 +779,14 @@ run (void *cls,
bc.exchange_payto,
"short-lived-reserve"),
TALER_TESTING_cmd_exec_wirewatch ("short-lived-aggregation",
CONFIG_FILE_EXPIRE_RESERVE_NOW),
config_file_expire_reserve_now),
TALER_TESTING_cmd_exec_closer ("close-reserves",
CONFIG_FILE_EXPIRE_RESERVE_NOW,
config_file_expire_reserve_now,
"EUR:5",
"EUR:0.01",
"short-lived-reserve"),
TALER_TESTING_cmd_exec_transfer ("close-reserves-transfer",
CONFIG_FILE_EXPIRE_RESERVE_NOW),
config_file_expire_reserve_now),
TALER_TESTING_cmd_status ("short-lived-status",
"short-lived-reserve",
@ -837,7 +836,7 @@ run (void *cls,
TALER_TESTING_cmd_revoke ("revoke-1-EUR:1",
MHD_HTTP_OK,
"recoup-withdraw-coin-2a",
CONFIG_FILE),
config_file),
/* Check recoup is failing for the coin with the reused coin key */
TALER_TESTING_cmd_recoup ("recoup-2x",
MHD_HTTP_CONFLICT,
@ -909,10 +908,10 @@ run (void *cls,
"EUR:20");
reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 1]
= TALER_TESTING_cmd_exec_wirewatch ("reserve-open-close-wirewatch",
CONFIG_FILE_EXPIRE_RESERVE_NOW);
config_file_expire_reserve_now);
reserve_open_close[(i * RESERVE_OPEN_CLOSE_CHUNK) + 2]
= TALER_TESTING_cmd_exec_closer ("reserve-open-close-aggregation",
CONFIG_FILE_EXPIRE_RESERVE_NOW,
config_file_expire_reserve_now,
"EUR:19.99",
"EUR:0.01",
"reserve-open-close-key");
@ -936,9 +935,9 @@ run (void *cls,
MHD_HTTP_NO_CONTENT,
false),
TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys",
CONFIG_FILE),
config_file),
TALER_TESTING_cmd_exec_offline_sign_fees ("offline-sign-fees",
CONFIG_FILE,
config_file,
"EUR:0.01",
"EUR:0.01"),
TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
@ -978,25 +977,34 @@ int
main (int argc,
char *const *argv)
{
const char *cipher;
(void) argc;
(void) argv;
/* These environment variables get in the way... */
unsetenv ("XDG_DATA_HOME");
unsetenv ("XDG_CONFIG_HOME");
GNUNET_log_setup ("test-exchange-api",
GNUNET_log_setup (argv[0],
"INFO",
NULL);
cipher = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
GNUNET_assert (NULL != cipher);
GNUNET_asprintf (&config_file,
"test_exchange_api-%s.conf",
cipher);
GNUNET_asprintf (&config_file_expire_reserve_now,
"test_exchange_api_expire_reserve_now-%s.conf",
cipher);
/* Check fakebank port is available and get config */
if (GNUNET_OK !=
TALER_TESTING_prepare_fakebank (CONFIG_FILE,
TALER_TESTING_prepare_fakebank (config_file,
"exchange-account-2",
&bc))
return 77;
TALER_TESTING_cleanup_files (CONFIG_FILE);
TALER_TESTING_cleanup_files (config_file);
/* @helpers. Run keyup, create tables, ... Note: it
* fetches the port number from config in order to see
* if it's available. */
switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
switch (TALER_TESTING_prepare_exchange (config_file,
GNUNET_YES,
&ec))
{
@ -1013,7 +1021,7 @@ main (int argc,
*/
TALER_TESTING_setup_with_exchange (&run,
NULL,
CONFIG_FILE))
config_file))
return 1;
break;
default:

View File

@ -0,0 +1,98 @@
# This file is in the public domain.
#
[PATHS]
# Persistent data storage for the testcase
TALER_TEST_HOME = test_exchange_api_keys_cherry_picking_home/
TALER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/${USER:-}/taler-system-runtime/
# Persistent data storage
TALER_DATA_HOME = $TALER_HOME/.local/share/taler/
# Configuration files
TALER_CONFIG_HOME = $TALER_HOME/.config/taler/
# Cached data, no big deal if lost
TALER_CACHE_HOME = $TALER_HOME/.cache/taler/
[taler]
# Currency supported by the exchange (can only be one)
CURRENCY = EUR
[taler-exchange-secmod-cs]
# Reduce from 1 year to speed up test
LOOKAHEAD_SIGN = 24 days
[taler-exchange-secmod-eddsa]
# Reduce from 1 year to speed up test
LOOKAHEAD_SIGN = 24 days
# Reduce from 12 weeks to ensure we have multiple
DURATION = 14 days
[auditor]
BASE_URL = "http://localhost:8083/"
# HTTP port the auditor listens to
PORT = 8083
[exchange]
# HTTP port the exchange listens to
PORT = 8081
# Master public key used to sign the exchange's various keys
MASTER_PUBLIC_KEY = 98NJW3CQHZQGQXTY3K85K531XKPAPAVV4Q5V8PYYRR00NJGZWNVG
# How to access our database
DB = postgres
# Base URL of the exchange. Must be set to a URL where the
# exchange (or the twister) is actually listening.
BASE_URL = "http://localhost:8081/"
[exchangedb-postgres]
CONFIG = "postgres:///talercheck"
[auditordb-postgres]
CONFIG = "postgres:///talercheck"
[exchange-account-1]
PAYTO_URI = payto://x-taler-bank/localhost/42
[exchange-accountcredentials-1]
WIRE_GATEWAY_URL = "http://localhost:9082/42/"
[exchange-account-2]
PAYTO_URI = payto://x-taler-bank/localhost/2
ENABLE_DEBIT = YES
ENABLE_CREDIT = YES
[exchange-accountcredentials-2]
WIRE_GATEWAY_URL = "http://localhost:9082/2/"
# Authentication information for basic authentication
TALER_BANK_AUTH_METHOD = "basic"
USERNAME = user
PASSWORD = pass
[bank]
HTTP_PORT=8082
[taler-exchange-secmod-cs]
OVERLAP_DURATION = 1 s
LOOKAHEAD_SIGN = 20 s
[taler-exchange-secmod-eddsa]
OVERLAP_DURATION = 1 s
DURATION = 30 s
LOOKAHEAD_SIGN = 20 s
[coin_eur_1]
value = EUR:1
duration_withdraw = 5 s
duration_spend = 6 s
duration_legal = 7 s
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS

View File

@ -95,4 +95,5 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024

View File

@ -29,6 +29,7 @@ lished
#include "taler_exchange_service.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_testing_lib.h>
#include <microhttpd.h>
#include "taler_bank_service.h"
#include "taler_fakebank_lib.h"
@ -39,7 +40,7 @@ lished
* Configuration file we use. One (big) configuration is used
* for the various components for this test.
*/
#define CONFIG_FILE "test_exchange_api_keys_cherry_picking.conf"
static char *config_file;
/**
* Exchange configuration data.
@ -66,11 +67,11 @@ run (void *cls,
MHD_HTTP_NO_CONTENT,
false),
TALER_TESTING_cmd_exec_offline_sign_fees ("offline-sign-fees",
CONFIG_FILE,
config_file,
"EUR:0.01",
"EUR:0.01"),
TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys",
CONFIG_FILE),
config_file),
TALER_TESTING_cmd_check_keys_pull_all_keys ("initial-/keys",
1),
TALER_TESTING_cmd_sleep ("sleep",
@ -109,19 +110,25 @@ int
main (int argc,
char *const *argv)
{
const char *cipher;
(void) argc;
(void) argv;
/* These environment variables get in the way... */
unsetenv ("XDG_DATA_HOME");
unsetenv ("XDG_CONFIG_HOME");
GNUNET_log_setup ("test-exchange-api-cherry-picking",
GNUNET_log_setup (argv[0],
"DEBUG",
NULL);
TALER_TESTING_cleanup_files (CONFIG_FILE);
cipher = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
GNUNET_assert (NULL != cipher);
GNUNET_asprintf (&config_file,
"test_exchange_api_keys_cherry_picking-%s.conf",
cipher);
TALER_TESTING_cleanup_files (config_file);
/* @helpers. Run keyup, create tables, ... Note: it
* fetches the port number from config in order to see
* if it's available. */
switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
switch (TALER_TESTING_prepare_exchange (config_file,
GNUNET_YES,
&ec))
{
@ -138,7 +145,7 @@ main (int argc,
*/
TALER_TESTING_setup_with_exchange (&run,
NULL,
CONFIG_FILE))
config_file))
return 1;
break;
default:

View File

@ -31,6 +31,7 @@
#include "taler_exchange_service.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_testing_lib.h>
#include <microhttpd.h>
#include "taler_bank_service.h"
#include "taler_fakebank_lib.h"
@ -40,7 +41,7 @@
* Configuration file we use. One (big) configuration is used
* for the various components for this test.
*/
#define CONFIG_FILE "test_exchange_api_keys_cherry_picking.conf"
static char *config_file;
/**
* Exchange configuration data.
@ -67,7 +68,7 @@ run (void *cls,
MHD_HTTP_NO_CONTENT,
false),
TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys",
CONFIG_FILE),
config_file),
TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
1),
TALER_TESTING_cmd_check_keys ("first-download",
@ -89,18 +90,25 @@ int
main (int argc,
char *const *argv)
{
const char *cipher;
(void) argc;
(void) argv;
/* These environment variables get in the way... */
unsetenv ("XDG_DATA_HOME");
unsetenv ("XDG_CONFIG_HOME");
GNUNET_log_setup ("test-exchange-api-overlapping-keys-bug",
"DEBUG", NULL);
TALER_TESTING_cleanup_files (CONFIG_FILE);
GNUNET_log_setup (argv[0],
"DEBUG",
NULL);
cipher = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
GNUNET_assert (NULL != cipher);
GNUNET_asprintf (&config_file,
"test_exchange_api_keys_cherry_picking-%s.conf",
cipher);
TALER_TESTING_cleanup_files (config_file);
/* @helpers. Run keyup, create tables, ... Note: it
* fetches the port number from config in order to see
* if it's available. */
switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
switch (TALER_TESTING_prepare_exchange (config_file,
GNUNET_YES,
&ec))
{
@ -117,7 +125,7 @@ main (int argc,
*/
TALER_TESTING_setup_with_exchange (&run,
NULL,
CONFIG_FILE))
config_file))
return 1;
break;
default:

View File

@ -29,6 +29,7 @@
#include "taler_exchange_service.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_testing_lib.h>
#include <microhttpd.h>
#include "taler_bank_service.h"
#include "taler_fakebank_lib.h"
@ -38,7 +39,7 @@
* Configuration file we use. One (big) configuration is used
* for the various components for this test.
*/
#define CONFIG_FILE "test_exchange_api.conf"
static char *config_file;
/**
* Exchange configuration data.
@ -70,7 +71,7 @@ run (void *cls,
MHD_HTTP_NO_CONTENT,
false),
TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys",
CONFIG_FILE),
config_file),
TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
1),
/**
@ -90,7 +91,7 @@ run (void *cls,
* Run wire-watch to trigger the reserve creation.
*/
TALER_TESTING_cmd_exec_wirewatch ("wirewatch-4",
CONFIG_FILE),
config_file),
/* Withdraw a 5 EUR coin, at fee of 1 ct */
TALER_TESTING_cmd_withdraw_amount ("withdraw-revocation-coin-1",
"create-reserve-1",
@ -144,12 +145,12 @@ run (void *cls,
TALER_TESTING_cmd_revoke ("revoke-2-EUR:5",
MHD_HTTP_OK,
"refresh-melt-1",
CONFIG_FILE),
config_file),
/* Also make fully spent coin invalid (should be same denom) */
TALER_TESTING_cmd_revoke ("revoke-2-EUR:5",
MHD_HTTP_OK,
"withdraw-revocation-coin-2",
CONFIG_FILE),
config_file),
/* Refund fully spent coin (which should fail) */
TALER_TESTING_cmd_recoup ("recoup-fully-spent",
MHD_HTTP_CONFLICT,
@ -211,12 +212,12 @@ run (void *cls,
TALER_TESTING_cmd_revoke ("revoke-3-EUR:0.1",
MHD_HTTP_OK,
"refresh-reveal-2",
CONFIG_FILE),
config_file),
/* Revoke also original coin denomination */
TALER_TESTING_cmd_revoke ("revoke-4-EUR:5",
MHD_HTTP_OK,
"withdraw-revocation-coin-1",
CONFIG_FILE),
config_file),
/* Refund coin EUR:0.1 to original coin, creating zombie! */
TALER_TESTING_cmd_recoup_refresh ("recoup-2",
MHD_HTTP_OK,
@ -248,25 +249,31 @@ int
main (int argc,
char *const *argv)
{
const char *cipher;
(void) argc;
(void) argv;
/* These environment variables get in the way... */
unsetenv ("XDG_DATA_HOME");
unsetenv ("XDG_CONFIG_HOME");
GNUNET_log_setup ("test-exchange-api-revocation",
GNUNET_log_setup (argv[0],
"INFO",
NULL);
cipher = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
GNUNET_assert (NULL != cipher);
GNUNET_asprintf (&config_file,
"test_exchange_api-%s.conf",
cipher);
/* Check fakebank port is available and get config */
if (GNUNET_OK !=
TALER_TESTING_prepare_fakebank (CONFIG_FILE,
TALER_TESTING_prepare_fakebank (config_file,
"exchange-account-2",
&bc))
return 77;
TALER_TESTING_cleanup_files (CONFIG_FILE);
TALER_TESTING_cleanup_files (config_file);
/* @helpers. Run keyup, create tables, ... Note: it
* fetches the port number from config in order to see
* if it's available. */
switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
switch (TALER_TESTING_prepare_exchange (config_file,
GNUNET_YES,
&ec))
{
@ -283,7 +290,7 @@ main (int argc,
*/
TALER_TESTING_setup_with_exchange (&run,
NULL,
CONFIG_FILE))
config_file))
return 1;
break;
default:

View File

@ -29,6 +29,7 @@
#include "taler_exchange_service.h"
#include "taler_json_lib.h"
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_testing_lib.h>
#include <microhttpd.h>
#include "taler_bank_service.h"
#include "taler_fakebank_lib.h"
@ -40,7 +41,7 @@
* Configuration file we use. One (big) configuration is used
* for the various components for this test.
*/
#define CONFIG_FILE "test_exchange_api_twisted.conf"
static char *config_file;
/**
* (real) Twister URL. Used at startup time to check if it runs.
@ -73,7 +74,7 @@ static struct TALER_TESTING_Command
CMD_EXEC_WIREWATCH (const char *label)
{
return TALER_TESTING_cmd_exec_wirewatch (label,
CONFIG_FILE);
config_file);
}
@ -142,7 +143,7 @@ run (void *cls,
NULL),
/* Trigger 409 Conflict. */
TALER_TESTING_cmd_flip_upload ("flip-upload",
CONFIG_FILE,
config_file,
"transfer_privs.0"),
TALER_TESTING_cmd_refresh_reveal ("refresh-(flipped-)reveal",
"refresh-melt",
@ -178,7 +179,7 @@ run (void *cls,
"USD:5",
"deposit-refund-1"),
TALER_TESTING_cmd_flip_upload ("flip-upload",
CONFIG_FILE,
config_file,
"merchant_sig"),
TALER_TESTING_cmd_refund ("refund-bad-sig",
MHD_HTTP_FORBIDDEN,
@ -217,7 +218,7 @@ run (void *cls,
*/
struct TALER_TESTING_Command expired_keys[] = {
TALER_TESTING_cmd_modify_header_dl ("modify-expiration",
CONFIG_FILE,
config_file,
MHD_HTTP_HEADER_EXPIRES,
"Wed, 19 Jan 586524 08:01:49 GMT"),
TALER_TESTING_cmd_check_keys_pull_all_keys (
@ -243,7 +244,7 @@ run (void *cls,
MHD_HTTP_NO_CONTENT,
false),
TALER_TESTING_cmd_exec_offline_sign_keys ("offline-sign-future-keys",
CONFIG_FILE),
config_file),
TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
1),
TALER_TESTING_cmd_batch ("refresh-reveal-409-conflict",
@ -283,26 +284,31 @@ int
main (int argc,
char *const *argv)
{
const char *cipher;
int ret;
(void) argc;
(void) argv;
/* These environment variables get in the way... */
unsetenv ("XDG_DATA_HOME");
unsetenv ("XDG_CONFIG_HOME");
GNUNET_log_setup ("test-exchange-api-twisted",
GNUNET_log_setup (argv[0],
"DEBUG",
NULL);
cipher = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
GNUNET_assert (NULL != cipher);
GNUNET_asprintf (&config_file,
"test_exchange_api_twisted-%s.conf",
cipher);
if (GNUNET_OK !=
TALER_TESTING_prepare_fakebank (CONFIG_FILE,
TALER_TESTING_prepare_fakebank (config_file,
"exchange-account-2",
&bc))
return 77;
if (NULL == (twister_url = TALER_TWISTER_prepare_twister
(CONFIG_FILE)))
(config_file)))
return 77;
TALER_TESTING_cleanup_files (CONFIG_FILE);
switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
TALER_TESTING_cleanup_files (config_file);
switch (TALER_TESTING_prepare_exchange (config_file,
GNUNET_YES,
&ec))
{
@ -312,11 +318,11 @@ main (int argc,
case GNUNET_NO:
return 77;
case GNUNET_OK:
if (NULL == (twisterd = TALER_TWISTER_run_twister (CONFIG_FILE)))
if (NULL == (twisterd = TALER_TWISTER_run_twister (config_file)))
return 77;
ret = TALER_TESTING_setup_with_exchange (&run,
NULL,
CONFIG_FILE);
config_file);
purge_process (twisterd);
GNUNET_free (twister_url);

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2020 Taler Systems SA
Copyright (C) 2020-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as
@ -25,6 +25,7 @@
#include "taler_util.h"
#include "taler_exchange_service.h"
#include <gnunet/gnunet_util_lib.h>
#include <gnunet/gnunet_testing_lib.h>
#include <microhttpd.h>
#include "taler_testing_lib.h"
@ -32,7 +33,7 @@
* Configuration file we use. One (big) configuration is used
* for the various components for this test.
*/
#define CONFIG_FILE "test_exchange_api.conf"
static char *config_file;
/**
@ -139,7 +140,7 @@ run (void *cls,
MHD_HTTP_NO_CONTENT,
false),
TALER_TESTING_cmd_exec_offline_sign_keys ("download-future-keys",
CONFIG_FILE),
config_file),
TALER_TESTING_cmd_check_keys_pull_all_keys ("refetch /keys",
1),
TALER_TESTING_cmd_end ()
@ -156,25 +157,31 @@ int
main (int argc,
char *const *argv)
{
const char *cipher;
(void) argc;
(void) argv;
/* These environment variables get in the way... */
unsetenv ("XDG_DATA_HOME");
unsetenv ("XDG_CONFIG_HOME");
GNUNET_log_setup ("test-exchange-management-api",
GNUNET_log_setup (argv[0],
"INFO",
NULL);
/* Check fakebank port is available and get config */
cipher = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
GNUNET_assert (NULL != cipher);
GNUNET_asprintf (&config_file,
"test_exchange_api-%s.conf",
cipher);
if (GNUNET_OK !=
TALER_TESTING_prepare_fakebank (CONFIG_FILE,
TALER_TESTING_prepare_fakebank (config_file,
"exchange-account-2",
&bc))
return 77;
TALER_TESTING_cleanup_files (CONFIG_FILE);
TALER_TESTING_cleanup_files (config_file);
/* @helpers. Create tables, ... Note: it
* fetches the port number from config in order to see
* if it's available. */
switch (TALER_TESTING_prepare_exchange (CONFIG_FILE,
switch (TALER_TESTING_prepare_exchange (config_file,
GNUNET_YES, /* reset DB? */
&ec))
{
@ -191,7 +198,7 @@ main (int argc,
*/
TALER_TESTING_setup_with_exchange (&run,
NULL,
CONFIG_FILE))
config_file))
return 1;
break;
default:

View File

@ -110,8 +110,20 @@ fee_withdraw = EUR:0.00
fee_deposit = EUR:0.00
fee_refresh = EUR:0.01
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_eur_ct_2]
value = EUR:0.01
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.00
fee_deposit = EUR:0.00
fee_refresh = EUR:0.01
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_ct_10]
value = EUR:0.10
duration_withdraw = 7 days
@ -121,8 +133,20 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_eur_ct_11]
value = EUR:0.10
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_1]
value = EUR:1
duration_withdraw = 7 days
@ -132,8 +156,20 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_eur_2]
value = EUR:1
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_5]
value = EUR:5
duration_withdraw = 7 days
@ -143,8 +179,20 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_eur_6]
value = EUR:5
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS
[coin_eur_10]
value = EUR:10
duration_withdraw = 7 days
@ -154,4 +202,16 @@ fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = RSA
rsa_keysize = 1024
[coin_eur_11]
value = EUR:10
duration_withdraw = 7 days
duration_spend = 2 years
duration_legal = 3 years
fee_withdraw = EUR:0.01
fee_deposit = EUR:0.01
fee_refresh = EUR:0.03
fee_refund = EUR:0.01
CIPHER = CS

View File

@ -293,7 +293,7 @@ deposit_run (void *cls,
struct TALER_MerchantPublicKeyP merchant_pub;
struct TALER_PrivateContractHash h_contract_terms;
enum TALER_ErrorCode ec;
struct TALER_WireSalt wire_salt;
struct TALER_WireSaltP wire_salt;
const char *payto_uri;
struct GNUNET_JSON_Specification spec[] = {
GNUNET_JSON_spec_string ("payto_uri",

View File

@ -201,23 +201,27 @@ insert_deposit_run (void *cls,
struct TALER_CoinPubHash c_hash;
struct TALER_PlanchetDetail pd;
struct TALER_BlindedDenominationSignature bds;
struct TALER_PlanchetSecretsP ps;
struct TALER_ExchangeWithdrawValues alg_values;
union TALER_DenominationBlindingKeyP bks;
TALER_blinding_secret_create (&bks);
alg_values.cipher = TALER_DENOMINATION_RSA;
TALER_planchet_blinding_secret_create (&ps,
&alg_values,
&bks);
GNUNET_assert (GNUNET_OK ==
TALER_denom_blind (&dpk,
&bks,
NULL, /* FIXME-Oec */
&deposit.coin.coin_pub,
&alg_values,
&c_hash,
&pd.coin_ev,
&pd.coin_ev_size));
&pd.blinded_planchet));
GNUNET_assert (GNUNET_OK ==
TALER_denom_sign_blinded (&bds,
&denom_priv,
pd.coin_ev,
pd.coin_ev_size));
GNUNET_free (pd.coin_ev);
&pd.blinded_planchet));
TALER_blinded_planchet_free (&pd.blinded_planchet);
GNUNET_assert (GNUNET_OK ==
TALER_denom_sig_unblind (&deposit.coin.denom_sig,
&bds,

View File

@ -237,12 +237,12 @@ recoup_run (void *cls,
struct RecoupState *ps = cls;
const struct TALER_TESTING_Command *coin_cmd;
const struct TALER_CoinSpendPrivateKeyP *coin_priv;
const union TALER_DenominationBlindingKeyP *blinding_key;
const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
const struct TALER_DenominationSignature *coin_sig;
struct TALER_PlanchetSecretsP planchet;
const struct TALER_PlanchetSecretsP *planchet;
char *cref;
unsigned int idx;
const struct TALER_ExchangeWithdrawValues *ewv;
ps->is = is;
if (GNUNET_OK !=
@ -264,7 +264,6 @@ recoup_run (void *cls,
TALER_TESTING_interpreter_fail (is);
return;
}
if (GNUNET_OK !=
TALER_TESTING_get_trait_coin_priv (coin_cmd,
idx,
@ -274,18 +273,23 @@ recoup_run (void *cls,
TALER_TESTING_interpreter_fail (is);
return;
}
if (GNUNET_OK !=
TALER_TESTING_get_trait_blinding_key (coin_cmd,
TALER_TESTING_get_trait_exchange_wd_value (coin_cmd,
idx,
&blinding_key))
&ewv))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
if (GNUNET_OK !=
TALER_TESTING_get_trait_planchet_secret (coin_cmd,
&planchet))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
planchet.coin_priv = *coin_priv;
planchet.blinding_key = *blinding_key;
GNUNET_CRYPTO_eddsa_key_get_public (
&coin_priv->eddsa_priv,
&ps->reserve_history.details.recoup_details.coin_pub.eddsa_pub);
@ -299,7 +303,6 @@ recoup_run (void *cls,
TALER_TESTING_interpreter_fail (is);
return;
}
if (GNUNET_OK !=
TALER_TESTING_get_trait_denom_sig (coin_cmd,
idx,
@ -309,15 +312,14 @@ recoup_run (void *cls,
TALER_TESTING_interpreter_fail (is);
return;
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Trying to recoup denomination '%s'\n",
TALER_B2S (&denom_pub->h_key));
ps->ph = TALER_EXCHANGE_recoup (is->exchange,
denom_pub,
coin_sig,
&planchet,
ewv,
planchet,
&recoup_cb,
ps);
GNUNET_assert (NULL != ps->ph);

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014-2018 Taler Systems SA
Copyright (C) 2014-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as
@ -231,10 +231,10 @@ recoup_refresh_run (void *cls,
struct RecoupRefreshState *ps = cls;
const struct TALER_TESTING_Command *coin_cmd;
const struct TALER_CoinSpendPrivateKeyP *coin_priv;
const union TALER_DenominationBlindingKeyP *blinding_key;
const struct TALER_EXCHANGE_DenomPublicKey *denom_pub;
const struct TALER_DenominationSignature *coin_sig;
struct TALER_PlanchetSecretsP planchet;
const struct TALER_PlanchetSecretsP *planchet;
const struct TALER_ExchangeWithdrawValues *ewv;
char *cref;
unsigned int idx;
@ -258,7 +258,6 @@ recoup_refresh_run (void *cls,
TALER_TESTING_interpreter_fail (is);
return;
}
if (GNUNET_OK !=
TALER_TESTING_get_trait_coin_priv (coin_cmd,
idx,
@ -268,18 +267,24 @@ recoup_refresh_run (void *cls,
TALER_TESTING_interpreter_fail (is);
return;
}
if (GNUNET_OK !=
TALER_TESTING_get_trait_blinding_key (coin_cmd,
TALER_TESTING_get_trait_exchange_wd_value (coin_cmd,
idx,
&blinding_key))
&ewv))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
if (GNUNET_OK !=
TALER_TESTING_get_trait_planchet_secrets (coin_cmd,
idx,
&planchet))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (is);
return;
}
planchet.coin_priv = *coin_priv;
planchet.blinding_key = *blinding_key;
if (GNUNET_OK !=
TALER_TESTING_get_trait_denom_pub (coin_cmd,
@ -308,8 +313,9 @@ recoup_refresh_run (void *cls,
ps->ph = TALER_EXCHANGE_recoup_refresh (is->exchange,
denom_pub,
coin_sig,
&planchet,
recoup_refresh_cb,
ewv,
planchet,
&recoup_refresh_cb,
ps);
GNUNET_assert (NULL != ps->ph);
}

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2018-2020 Taler Systems SA
Copyright (C) 2018-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
@ -91,9 +91,9 @@ struct RefreshMeltState
const char *coin_reference;
/**
* "Crypto data" used in the refresh operation.
* Data used in the refresh operation.
*/
json_t *refresh_data;
struct TALER_EXCHANGE_RefreshData refresh_data;
/**
* Reference to a previous melt command.
@ -116,6 +116,22 @@ struct RefreshMeltState
*/
struct TALER_EXCHANGE_DenomPublicKey *fresh_pks;
/**
* Array of @a num_fresh_coins of exchange values contributed to the refresh operation
*/
struct TALER_ExchangeWithdrawValues *alg_values;
/**
* Array of @a num_fresh_coins of blinding key secrets
* created during the melt operation.
*/
union TALER_DenominationBlindingKeyP *bks;
/**
* Entropy seed for the refresh-melt operation.
*/
struct TALER_PlanchetSecretsP ps;
/**
* Private key of the dirty coin being melted.
*/
@ -162,7 +178,7 @@ struct RefreshMeltState
* exchange to pick any previous /rerfesh/melt operation from
* the database.
*/
unsigned int double_melt;
bool double_melt;
/**
* How often should we retry on (transient) failures?
@ -337,7 +353,7 @@ static void
reveal_cb (void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr,
unsigned int num_coins,
const struct TALER_PlanchetSecretsP *coin_privs,
const struct TALER_CoinSpendPrivateKeyP *coin_privs,
const struct TALER_DenominationSignature *sigs)
{
struct RefreshRevealState *rrs = cls;
@ -402,6 +418,7 @@ reveal_cb (void *cls,
for (unsigned int i = 0; i<num_coins; i++)
{
struct TALER_TESTING_FreshCoinData *fc = &rrs->fresh_coins[i];
const union TALER_DenominationBlindingKeyP *bks;
if (GNUNET_OK !=
TALER_TESTING_get_trait_denom_pub (melt_cmd,
@ -412,8 +429,17 @@ reveal_cb (void *cls,
TALER_TESTING_interpreter_fail (rrs->is);
return;
}
fc->coin_priv = coin_privs[i].coin_priv;
fc->blinding_key = coin_privs[i].blinding_key;
if (GNUNET_OK !=
TALER_TESTING_get_trait_blinding_key (melt_cmd,
i,
&bks))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (rrs->is);
return;
}
fc->coin_priv = coin_privs[i];
fc->blinding_key = *bks;
TALER_denom_sig_deep_copy (&fc->sig,
&sigs[i]);
}
@ -461,9 +487,13 @@ refresh_reveal_run (void *cls,
TALER_TESTING_interpreter_fail (rrs->is);
return;
}
// FIXME: use trait for 'rms'!
rms = melt_cmd->cls;
rrs->rrh = TALER_EXCHANGE_refreshes_reveal (is->exchange,
rms->refresh_data,
&rms->ps,
&rms->refresh_data,
rms->num_fresh_coins,
rms->alg_values,
rms->noreveal_index,
&reveal_cb,
rrs);
@ -763,6 +793,7 @@ refresh_link_run (void *cls,
/* find reserve_withdraw command */
{
// FIXME: use trait!
rms = melt_cmd->cls;
coin_cmd = TALER_TESTING_interpreter_lookup_command (rls->is,
rms->coin_reference);
@ -856,11 +887,6 @@ do_melt_retry (void *cls)
rms->retry_task = NULL;
rms->is->commands[rms->is->ip].last_req_time
= GNUNET_TIME_absolute_get ();
if (NULL != rms->refresh_data)
{
json_decref (rms->refresh_data);
rms->refresh_data = NULL;
}
melt_run (rms,
NULL,
rms->is);
@ -874,6 +900,9 @@ do_melt_retry (void *cls)
*
* @param cls closure.
* @param hr HTTP response details
* @param num_coins number of fresh coins to be created, length of the @a exchange_vals array, 0 if the operation failed
* @param alg_values array @a num_coins of exchange values contributed to the refresh operation
* @param bks array of @a num_coins blinding keys used to blind the fresh coins
* @param noreveal_index choice by the exchange in the
* cut-and-choose protocol, UINT16_MAX on error.
* @param exchange_pub public key the exchange used for signing.
@ -881,6 +910,9 @@ do_melt_retry (void *cls)
static void
melt_cb (void *cls,
const struct TALER_EXCHANGE_HttpResponse *hr,
unsigned int num_coins,
const struct TALER_ExchangeWithdrawValues *alg_values,
const union TALER_DenominationBlindingKeyP *bks,
uint32_t noreveal_index,
const struct TALER_ExchangePublicKeyP *exchange_pub)
{
@ -929,7 +961,27 @@ melt_cb (void *cls,
TALER_TESTING_interpreter_fail (rms->is);
return;
}
if (MHD_HTTP_OK == hr->http_status)
{
rms->noreveal_index = noreveal_index;
if (num_coins != rms->num_fresh_coins)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (rms->is);
return;
}
GNUNET_free (rms->alg_values);
rms->alg_values = GNUNET_new_array (num_coins,
struct TALER_ExchangeWithdrawValues);
memcpy (rms->alg_values,
alg_values,
num_coins * sizeof (struct TALER_ExchangeWithdrawValues));
rms->bks = GNUNET_new_array (num_coins,
union TALER_DenominationBlindingKeyP);
memcpy (rms->bks,
bks,
num_coins * sizeof (union TALER_DenominationBlindingKeyP));
}
if (0 != rms->total_backoff.rel_value_us)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@ -938,15 +990,16 @@ melt_cb (void *cls,
GNUNET_STRINGS_relative_time_to_string (rms->total_backoff,
GNUNET_YES));
}
if (GNUNET_YES == rms->double_melt)
if (rms->double_melt)
{
TALER_LOG_DEBUG ("Doubling the melt (%s)\n",
rms->is->commands[rms->is->ip].label);
rms->rmh = TALER_EXCHANGE_melt (rms->is->exchange,
rms->refresh_data,
&rms->ps,
&rms->refresh_data,
&melt_cb,
rms);
rms->double_melt = GNUNET_NO;
rms->double_melt = false;
return;
}
TALER_TESTING_interpreter_next (rms->is);
@ -978,13 +1031,14 @@ melt_run (void *cls,
melt_fresh_amounts = default_melt_fresh_amounts;
rms->is = is;
rms->noreveal_index = UINT16_MAX;
TALER_planchet_setup_random (&rms->ps);
for (num_fresh_coins = 0;
NULL != melt_fresh_amounts[num_fresh_coins];
num_fresh_coins++)
;
rms->num_fresh_coins = num_fresh_coins;
rms->fresh_pks = GNUNET_new_array
(num_fresh_coins,
rms->fresh_pks = GNUNET_new_array (
num_fresh_coins,
struct TALER_EXCHANGE_DenomPublicKey);
{
struct TALER_Amount melt_amount;
@ -994,8 +1048,9 @@ melt_run (void *cls,
const struct TALER_TESTING_Command *coin_command;
if (NULL == (coin_command
= TALER_TESTING_interpreter_lookup_command
(is, rms->coin_reference)))
= TALER_TESTING_interpreter_lookup_command (
is,
rms->coin_reference)))
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (rms->is);
@ -1011,7 +1066,6 @@ melt_run (void *cls,
TALER_TESTING_interpreter_fail (rms->is);
return;
}
if (GNUNET_OK !=
TALER_TESTING_get_trait_denom_sig (coin_command,
0,
@ -1044,12 +1098,13 @@ melt_run (void *cls,
GNUNET_break (0);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Failed to parse amount `%s' at index %u\n",
melt_fresh_amounts[i], i);
melt_fresh_amounts[i],
i);
TALER_TESTING_interpreter_fail (rms->is);
return;
}
fresh_pk = TALER_TESTING_find_pk
(TALER_EXCHANGE_get_keys (is->exchange), &fresh_amount);
fresh_pk = TALER_TESTING_find_pk (TALER_EXCHANGE_get_keys (is->exchange),
&fresh_amount);
if (NULL == fresh_pk)
{
GNUNET_break (0);
@ -1070,22 +1125,15 @@ melt_run (void *cls,
TALER_denom_pub_deep_copy (&rms->fresh_pks[i].key,
&fresh_pk->key);
} /* end for */
GNUNET_assert (NULL == rms->refresh_data);
rms->refresh_data
= TALER_EXCHANGE_refresh_prepare (rms->melt_priv,
&melt_amount,
melt_sig,
melt_denom_pub,
num_fresh_coins,
rms->fresh_pks);
if (NULL == rms->refresh_data)
{
GNUNET_break (0);
TALER_TESTING_interpreter_fail (rms->is);
return;
}
rms->refresh_data.melt_priv = *rms->melt_priv;
rms->refresh_data.melt_amount = melt_amount;
rms->refresh_data.melt_sig = *melt_sig;
rms->refresh_data.melt_pk = *melt_denom_pub;
rms->refresh_data.fresh_pks = rms->fresh_pks;
rms->refresh_data.fresh_pks_len = num_fresh_coins;
rms->rmh = TALER_EXCHANGE_melt (is->exchange,
rms->refresh_data,
&rms->ps,
&rms->refresh_data,
&melt_cb,
rms);
@ -1117,7 +1165,8 @@ melt_cleanup (void *cls,
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Command %u (%s) did not complete\n",
rms->is->ip, rms->is->commands[rms->is->ip].label);
rms->is->ip,
rms->is->commands[rms->is->ip].label);
TALER_EXCHANGE_melt_cancel (rms->rmh);
rms->rmh = NULL;
}
@ -1130,11 +1179,10 @@ melt_cleanup (void *cls,
{
for (unsigned int i = 0; i < rms->num_fresh_coins; i++)
TALER_denom_pub_free (&rms->fresh_pks[i].key);
}
GNUNET_free (rms->fresh_pks);
rms->fresh_pks = NULL;
json_decref (rms->refresh_data);
rms->refresh_data = NULL;
}
GNUNET_free (rms->alg_values);
GNUNET_free (rms->bks);
GNUNET_free (rms->melt_fresh_amounts);
GNUNET_free (rms);
}
@ -1168,6 +1216,9 @@ melt_traits (void *cls,
&rms->fresh_pks[index]),
TALER_TESTING_make_trait_coin_priv (0,
rms->melt_priv),
// ????
TALER_TESTING_make_trait_blinding_key (index,
&rms->bks[index]),
TALER_TESTING_trait_end ()
};
@ -1241,7 +1292,8 @@ TALER_TESTING_cmd_melt (const char *label,
rms = GNUNET_new (struct RefreshMeltState);
rms->coin_reference = coin_reference;
rms->expected_response_code = expected_response_code;
va_start (ap, expected_response_code);
va_start (ap,
expected_response_code);
GNUNET_assert (GNUNET_OK ==
parse_amounts (rms, ap));
va_end (ap);
@ -1271,8 +1323,9 @@ TALER_TESTING_cmd_melt_double (const char *label,
rms = GNUNET_new (struct RefreshMeltState);
rms->coin_reference = coin_reference;
rms->expected_response_code = expected_response_code;
rms->double_melt = GNUNET_YES;
va_start (ap, expected_response_code);
rms->double_melt = true;
va_start (ap,
expected_response_code);
GNUNET_assert (GNUNET_OK ==
parse_amounts (rms, ap));
va_end (ap);

View File

@ -99,6 +99,22 @@ struct WithdrawState
*/
struct TALER_ReservePublicKeyP reserve_pub;
/**
* Private key of the coin.
*/
struct TALER_CoinSpendPrivateKeyP coin_priv;
/**
* Blinding key used during the operation.
*/
union TALER_DenominationBlindingKeyP bks;
/**
* Values contributed from the exchange during the
* withdraw protocol.
*/
struct TALER_ExchangeWithdrawValues exchange_vals;
/**
* Interpreter state (during command).
*/
@ -263,6 +279,9 @@ reserve_withdraw_cb (void *cls,
case MHD_HTTP_OK:
TALER_denom_sig_deep_copy (&ws->sig,
&wr->details.success.sig);
ws->coin_priv = wr->details.success.coin_priv;
ws->bks = wr->details.success.bks;
ws->exchange_vals = wr->details.success.exchange_vals;
if (0 != ws->total_backoff.rel_value_us)
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
@ -392,7 +411,7 @@ withdraw_run (void *cls,
}
else
{
const struct TALER_CoinSpendPrivateKeyP *coin_priv;
const struct TALER_PlanchetSecretsP *ps;
const struct TALER_TESTING_Command *cref;
char *cstr;
unsigned int index;
@ -406,11 +425,9 @@ withdraw_run (void *cls,
GNUNET_assert (NULL != cref);
GNUNET_free (cstr);
GNUNET_assert (GNUNET_OK ==
TALER_TESTING_get_trait_coin_priv (cref,
index,
&coin_priv));
TALER_planchet_setup_random (&ws->ps);
ws->ps.coin_priv = *coin_priv;
TALER_TESTING_get_trait_planchet_secret (cref,
&ps));
ws->ps = *ps;
}
if (NULL == ws->pk)
{
@ -513,9 +530,12 @@ withdraw_traits (void *cls,
/* history entry MUST be first due to response code logic below! */
TALER_TESTING_make_trait_reserve_history (&ws->reserve_history),
TALER_TESTING_make_trait_coin_priv (0 /* only one coin */,
&ws->ps.coin_priv),
&ws->coin_priv),
TALER_TESTING_make_trait_planchet_secret (&ws->ps),
TALER_TESTING_make_trait_blinding_key (0 /* only one coin */,
&ws->ps.blinding_key),
&ws->bks),
TALER_TESTING_make_trait_exchange_wd_value (0 /* only one coin */,
&ws->exchange_vals),
TALER_TESTING_make_trait_denom_pub (0 /* only one coin */,
ws->pk),
TALER_TESTING_make_trait_denom_sig (0 /* only one coin */,

View File

@ -670,7 +670,7 @@ TALER_TESTING_prepare_fakebank (const char *config_filename,
json_t *
TALER_TESTING_make_wire_details (const char *payto)
{
struct TALER_WireSalt salt;
struct TALER_WireSaltP salt;
/* salt must be constant for aggregation tests! */
memset (&salt,

View File

@ -411,13 +411,6 @@ TALER_TESTING_prepare_exchange (const char *config_filename,
}
/**
* Find denomination key matching the given amount.
*
* @param keys array of keys to search
* @param amount coin value to look for
* @return NULL if no matching key was found
*/
const struct TALER_EXCHANGE_DenomPublicKey *
TALER_TESTING_find_pk (const struct TALER_EXCHANGE_Keys *keys,
const struct TALER_Amount *amount)
@ -608,9 +601,9 @@ TALER_TESTING_setup_with_exchange (TALER_TESTING_Main main_cb,
* @param[in] helpers the process handles.
*/
static void
stop_helpers (struct GNUNET_OS_Process *helpers[2])
stop_helpers (struct GNUNET_OS_Process *helpers[3])
{
for (unsigned int i = 0; i<2; i++)
for (unsigned int i = 0; i<3; i++)
{
if (NULL == helpers[i])
continue;
@ -632,7 +625,7 @@ stop_helpers (struct GNUNET_OS_Process *helpers[2])
*/
static enum GNUNET_GenericReturnValue
start_helpers (const char *config_filename,
struct GNUNET_OS_Process *helpers[2])
struct GNUNET_OS_Process *helpers[3])
{
char *dir;
const struct GNUNET_OS_ProjectData *pd;
@ -678,9 +671,26 @@ start_helpers (const char *config_filename,
NULL);
GNUNET_free (fn);
}
{
char *fn;
GNUNET_asprintf (&fn,
"%s/%s",
dir,
"taler-exchange-secmod-cs");
helpers[2] = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_ALL,
NULL, NULL, NULL,
fn,
"taler-exchange-secmod-cs",
"-c", config_filename,
"-L", "INFO",
NULL);
GNUNET_free (fn);
}
GNUNET_free (dir);
if ( (NULL == helpers[0]) ||
(NULL == helpers[1]) )
(NULL == helpers[1]) ||
(NULL == helpers[2]) )
{
stop_helpers (helpers);
return GNUNET_SYSERR;
@ -696,7 +706,7 @@ TALER_TESTING_setup_with_exchange_cfg (
{
const struct TALER_TESTING_SetupContext *setup_ctx = cls;
struct GNUNET_OS_Process *exchanged;
struct GNUNET_OS_Process *helpers[2];
struct GNUNET_OS_Process *helpers[3];
unsigned long long port;
char *serve;
char *base_url;
@ -755,6 +765,7 @@ TALER_TESTING_setup_with_exchange_cfg (
#endif
"taler-exchange-httpd",
"taler-exchange-httpd",
"-L", "INFO",
"-a", /* some tests may need timetravel */
"-c", setup_ctx->config_filename,
#if GNU_PARALLEL

View File

@ -691,7 +691,7 @@ main_wrapper_exchange_connect (void *cls)
*
* @param[in,out] is state to initialize
*/
static int
static enum GNUNET_GenericReturnValue
load_keys (struct TALER_TESTING_Interpreter *is)
{
char *fn;
@ -774,7 +774,7 @@ load_keys (struct TALER_TESTING_Interpreter *is)
*
* @param[in,out] is state to initialize
*/
static int
static enum GNUNET_GenericReturnValue
load_urls (struct TALER_TESTING_Interpreter *is)
{
if (GNUNET_OK !=
@ -804,7 +804,7 @@ load_urls (struct TALER_TESTING_Interpreter *is)
}
int
enum GNUNET_GenericReturnValue
TALER_TESTING_setup (TALER_TESTING_Main main_cb,
void *main_cb_cls,
const struct GNUNET_CONFIGURATION_Handle *cfg,
@ -839,7 +839,8 @@ TALER_TESTING_setup (TALER_TESTING_Main main_cb,
is.ctx = GNUNET_CURL_init
(&GNUNET_CURL_gnunet_scheduler_reschedule,
&is.rc);
GNUNET_CURL_enable_async_scope_header (is.ctx, "Taler-Correlation-Id");
GNUNET_CURL_enable_async_scope_header (is.ctx,
"Taler-Correlation-Id");
GNUNET_assert (NULL != is.ctx);
is.rc = GNUNET_CURL_gnunet_rc_create (is.ctx);

3
src/util/.gitignore vendored
View File

@ -1,8 +1,11 @@
taler-config
test_payto
taler-exchange-secmod-rsa
taler-exchange-secmod-cs
taler-exchange-secmod-eddsa
test_helper_rsa
test_helper_rsa_home/
test_helper_cs
test_helper_cs_home/
test_helper_eddsa
test_helper_eddsa_home/

View File

@ -12,17 +12,20 @@ pkgcfgdir = $(prefix)/share/taler/config.d/
pkgcfg_DATA = \
paths.conf \
taler-exchange-secmod-eddsa.conf \
taler-exchange-secmod-rsa.conf
taler-exchange-secmod-rsa.conf \
taler-exchange-secmod-cs.conf
EXTRA_DIST = \
$(pkgcfg_DATA) \
taler-config.in \
test_helper_eddsa.conf \
test_helper_rsa.conf
test_helper_rsa.conf \
test_helper_cs.conf
bin_PROGRAMS = \
taler-exchange-secmod-eddsa \
taler-exchange-secmod-rsa
taler-exchange-secmod-rsa \
taler-exchange-secmod-cs
bin_SCRIPTS = \
taler-config
@ -48,6 +51,16 @@ taler_exchange_secmod_rsa_LDADD = \
$(LIBGCRYPT_LIBS) \
$(XLIB)
taler_exchange_secmod_cs_SOURCES = \
taler-exchange-secmod-cs.c taler-exchange-secmod-cs.h \
secmod_common.c secmod_common.h
taler_exchange_secmod_cs_LDADD = \
libtalerutil.la \
-lgnunetutil \
-lpthread \
$(LIBGCRYPT_LIBS) \
$(XLIB)
taler_exchange_secmod_eddsa_SOURCES = \
taler-exchange-secmod-eddsa.c taler-exchange-secmod-eddsa.h \
secmod_common.c secmod_common.h
@ -68,6 +81,7 @@ libtalerutil_la_SOURCES = \
crypto.c \
crypto_helper_common.c crypto_helper_common.h \
crypto_helper_rsa.c \
crypto_helper_cs.c \
crypto_helper_esign.c \
crypto_wire.c \
denom.c \
@ -105,6 +119,7 @@ check_PROGRAMS = \
test_crypto \
test_helper_eddsa \
test_helper_rsa \
test_helper_cs \
test_payto \
test_url
@ -142,6 +157,12 @@ test_helper_rsa_LDADD = \
-lgnunetutil \
libtalerutil.la
test_helper_cs_SOURCES = \
test_helper_cs.c
test_helper_cs_LDADD = \
-lgnunetutil \
libtalerutil.la
test_url_SOURCES = \
test_url.c
test_url_LDADD = \

View File

@ -1,6 +1,6 @@
/*
This file is part of TALER
Copyright (C) 2014-2017 Taler Systems SA
Copyright (C) 2014-2022 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@ -116,7 +116,6 @@ TALER_link_derive_transfer_secret (
GNUNET_CRYPTO_ecdh_eddsa (&trans_priv->ecdhe_priv,
&coin_pub.eddsa_pub,
&ts->key));
}
@ -147,7 +146,18 @@ TALER_link_recover_transfer_secret (
void
TALER_planchet_setup_refresh (const struct TALER_TransferSecretP *secret_seed,
TALER_planchet_setup_random (
struct TALER_PlanchetSecretsP *ps)
{
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
ps,
sizeof (*ps));
}
void
TALER_transfer_secret_to_planchet_secret (
const struct TALER_TransferSecretP *secret_seed,
uint32_t coin_num_salt,
struct TALER_PlanchetSecretsP *ps)
{
@ -167,61 +177,296 @@ TALER_planchet_setup_refresh (const struct TALER_TransferSecretP *secret_seed,
void
TALER_planchet_setup_random (struct TALER_PlanchetSecretsP *ps)
TALER_planchet_secret_to_transfer_priv (
const struct TALER_PlanchetSecretsP *ps,
uint32_t cnc_num,
struct TALER_TransferPrivateKeyP *tpriv)
{
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG,
uint32_t be_salt = htonl (cnc_num);
GNUNET_assert (GNUNET_OK ==
GNUNET_CRYPTO_kdf (tpriv,
sizeof (*tpriv),
&be_salt,
sizeof (be_salt),
ps,
sizeof (*ps));
sizeof (*ps),
"taler-transfer-priv-derivation",
strlen ("taler-transfer-priv-derivation"),
NULL, 0));
}
void
TALER_cs_withdraw_nonce_derive (
const struct TALER_PlanchetSecretsP *ps,
struct TALER_CsNonce *nonce)
{
GNUNET_assert (GNUNET_YES ==
GNUNET_CRYPTO_kdf (nonce,
sizeof (*nonce),
"n",
strlen ("n"),
ps,
sizeof(*ps),
NULL,
0));
}
void
TALER_cs_refresh_nonce_derive (
const struct TALER_PlanchetSecretsP *ps,
uint32_t coin_num_salt,
struct TALER_CsNonce *nonce)
{
uint32_t be_salt = htonl (coin_num_salt);
GNUNET_assert (GNUNET_YES ==
GNUNET_CRYPTO_kdf (nonce,
sizeof (*nonce),
&be_salt,
sizeof (be_salt),
"refresh-n", // FIXME: value used in spec?
strlen ("refresh-n"),
ps,
sizeof(*ps),
NULL,
0));
}
void
TALER_planchet_blinding_secret_create (
const struct TALER_PlanchetSecretsP *ps,
const struct TALER_ExchangeWithdrawValues *alg_values,
union TALER_DenominationBlindingKeyP *bks)
{
switch (alg_values->cipher)
{
case TALER_DENOMINATION_INVALID:
GNUNET_break (0);
return;
case TALER_DENOMINATION_RSA:
GNUNET_assert (GNUNET_YES ==
GNUNET_CRYPTO_kdf (&bks->rsa_bks,
sizeof (bks->rsa_bks),
"bks",
strlen ("bks"),
ps,
sizeof(*ps),
NULL,
0));
return;
case TALER_DENOMINATION_CS:
GNUNET_assert (GNUNET_YES ==
GNUNET_CRYPTO_kdf (&bks->nonce,
sizeof (bks->nonce),
"bseed",
strlen ("bseed"),
ps,
sizeof(*ps),
&alg_values->details.cs_values,
sizeof(alg_values->details.cs_values),
NULL,
0));
return;
default:
GNUNET_break (0);
}
}
void
TALER_planchet_setup_coin_priv (
const struct TALER_PlanchetSecretsP *ps,
const struct TALER_ExchangeWithdrawValues *alg_values,
struct TALER_CoinSpendPrivateKeyP *coin_priv)
{
switch (alg_values->cipher)
{
case TALER_DENOMINATION_RSA:
GNUNET_assert (GNUNET_YES ==
GNUNET_CRYPTO_kdf (coin_priv,
sizeof (*coin_priv),
"coin",
strlen ("coin"),
ps,
sizeof(*ps),
NULL,
0));
break;
case TALER_DENOMINATION_CS:
GNUNET_assert (GNUNET_YES ==
GNUNET_CRYPTO_kdf (coin_priv,
sizeof (*coin_priv),
"coin",
strlen ("coin"),
ps,
sizeof(*ps),
&alg_values->details, /* Could be null on RSA case*/
sizeof(alg_values->details),
NULL,
0));
break;
default:
GNUNET_break (0);
return;
}
coin_priv->eddsa_priv.d[0] &= 248;
coin_priv->eddsa_priv.d[31] &= 127;
coin_priv->eddsa_priv.d[31] |= 64;
}
enum GNUNET_GenericReturnValue
TALER_planchet_prepare (const struct TALER_DenominationPublicKey *dk,
const struct TALER_PlanchetSecretsP *ps,
const struct TALER_ExchangeWithdrawValues *alg_values,
const union TALER_DenominationBlindingKeyP *bks,
const struct TALER_CoinSpendPrivateKeyP *coin_priv,
struct TALER_CoinPubHash *c_hash,
struct TALER_PlanchetDetail *pd)
struct TALER_PlanchetDetail *pd
)
{
struct TALER_CoinSpendPublicKeyP coin_pub;
GNUNET_CRYPTO_eddsa_key_get_public (&ps->coin_priv.eddsa_priv,
GNUNET_assert (alg_values->cipher == dk->cipher);
GNUNET_CRYPTO_eddsa_key_get_public (&coin_priv->eddsa_priv,
&coin_pub.eddsa_pub);
switch (dk->cipher)
{
case TALER_DENOMINATION_RSA:
if (GNUNET_OK !=
TALER_denom_blind (dk,
&ps->blinding_key,
bks,
NULL, /* FIXME-Oec */
&coin_pub,
alg_values,
c_hash,
&pd->coin_ev,
&pd->coin_ev_size))
&pd->blinded_planchet))
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
break;
case TALER_DENOMINATION_CS:
if (GNUNET_OK !=
TALER_denom_blind (dk,
bks,
NULL, /* FIXME-Oec */
&coin_pub,
alg_values,
c_hash,
&pd->blinded_planchet))
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
break;
default:
GNUNET_break (0);
return GNUNET_SYSERR;
}
pd->blinded_planchet.cipher = dk->cipher;
TALER_denom_pub_hash (dk,
&pd->denom_pub_hash);
return GNUNET_OK;
}
void
TALER_planchet_detail_free (struct TALER_PlanchetDetail *pd)
{
TALER_blinded_planchet_free (&pd->blinded_planchet);
}
void
TALER_blinded_planchet_free (struct TALER_BlindedPlanchet *blinded_planchet)
{
switch (blinded_planchet->cipher)
{
case TALER_DENOMINATION_RSA:
GNUNET_free (blinded_planchet->details.rsa_blinded_planchet.blinded_msg);
break;
case TALER_DENOMINATION_CS:
/* nothing to do for CS */
break;
default:
GNUNET_break (0);
}
}
enum GNUNET_GenericReturnValue
TALER_planchet_to_coin (
const struct TALER_DenominationPublicKey *dk,
const struct TALER_BlindedDenominationSignature *blind_sig,
const struct TALER_PlanchetSecretsP *ps,
const union TALER_DenominationBlindingKeyP *bks,
const struct TALER_CoinSpendPrivateKeyP *coin_priv,
const struct TALER_CoinPubHash *c_hash,
const struct TALER_ExchangeWithdrawValues *alg_values,
struct TALER_FreshCoin *coin)
{
struct TALER_DenominationSignature sig;
if (dk->cipher != blind_sig->cipher
&& dk->cipher != alg_values->cipher)
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
switch (dk->cipher)
{
case TALER_DENOMINATION_RSA:
if (GNUNET_OK !=
TALER_denom_sig_unblind (&sig,
blind_sig,
&ps->blinding_key,
bks,
dk))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
break;
case TALER_DENOMINATION_CS:
{
struct GNUNET_CRYPTO_CsC c[2];
struct GNUNET_CRYPTO_CsBlindingSecret bs[2];
struct TALER_DenominationCSPublicRPairP r_pub_blind;
GNUNET_CRYPTO_cs_blinding_secrets_derive (&bks->nonce,
bs);
GNUNET_CRYPTO_cs_calc_blinded_c (
bs,
alg_values->details.cs_values.r_pub_pair.r_pub,
&dk->details.cs_public_key,
&c_hash->hash,
sizeof(struct GNUNET_HashCode),
c,
r_pub_blind.r_pub);
sig.details.cs_signature.r_point
= r_pub_blind.r_pub[blind_sig->details.blinded_cs_answer.b];
if (GNUNET_OK !=
TALER_denom_sig_unblind (&sig,
blind_sig,
bks,
dk))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
break;
}
default:
GNUNET_break (0);
return GNUNET_SYSERR;
}
if (GNUNET_OK !=
TALER_denom_pub_verify (dk,
&sig,
@ -231,8 +476,9 @@ TALER_planchet_to_coin (
TALER_denom_sig_free (&sig);
return GNUNET_SYSERR;
}
coin->sig = sig;
coin->coin_priv = ps->coin_priv;
coin->coin_priv = *coin_priv;
return GNUNET_OK;
}
@ -294,9 +540,8 @@ TALER_refresh_get_commitment (struct TALER_RefreshCommitmentP *rc,
{
const struct TALER_RefreshCoinData *rcd = &rce->new_coins[j];
GNUNET_CRYPTO_hash_context_read (hash_context,
rcd->coin_ev,
rcd->coin_ev_size);
TALER_blinded_planchet_hash (&rcd->blinded_planchet,
hash_context);
}
}
@ -306,14 +551,39 @@ TALER_refresh_get_commitment (struct TALER_RefreshCommitmentP *rc,
}
void
TALER_coin_ev_hash (const void *coin_ev,
size_t coin_ev_size,
enum GNUNET_GenericReturnValue
TALER_coin_ev_hash (const struct TALER_BlindedPlanchet *blinded_planchet,
const struct TALER_DenominationHash *denom_hash,
struct TALER_BlindedCoinHash *bch)
{
GNUNET_CRYPTO_hash (coin_ev,
coin_ev_size,
struct GNUNET_HashContext *hash_context;
hash_context = GNUNET_CRYPTO_hash_context_start ();
GNUNET_CRYPTO_hash_context_read (hash_context,
denom_hash,
sizeof(*denom_hash));
switch (blinded_planchet->cipher)
{
case TALER_DENOMINATION_RSA:
GNUNET_CRYPTO_hash_context_read (
hash_context,
blinded_planchet->details.rsa_blinded_planchet.blinded_msg,
blinded_planchet->details.rsa_blinded_planchet.blinded_msg_size);
break;
case TALER_DENOMINATION_CS:
GNUNET_CRYPTO_hash_context_read (
hash_context,
&blinded_planchet->details.cs_blinded_planchet.nonce,
sizeof (blinded_planchet->details.cs_blinded_planchet.nonce));
break;
default:
GNUNET_break (0);
GNUNET_CRYPTO_hash_context_abort (hash_context);
return GNUNET_SYSERR;
}
GNUNET_CRYPTO_hash_context_finish (hash_context,
&bch->hash);
return GNUNET_OK;
}
@ -340,11 +610,9 @@ TALER_coin_pub_hash (const struct TALER_CoinSpendPublicKeyP *coin_pub,
GNUNET_memcpy (&data[0],
&coin_pub->eddsa_pub,
key_s);
GNUNET_memcpy (&data[key_s],
age_commitment_hash,
age_s);
GNUNET_CRYPTO_hash (&data,
key_s + age_s,
&coin_h->hash);

815
src/util/crypto_helper_cs.c Normal file
View File

@ -0,0 +1,815 @@
/*
This file is part of TALER
Copyright (C) 2020, 2021 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
/**
* @file util/crypto_helper_cs.c
* @brief utility functions for running out-of-process private key operations
* @author Christian Grothoff
*/
#include "platform.h"
#include "taler_util.h"
#include "taler_signatures.h"
#include "taler-exchange-secmod-cs.h"
#include <poll.h>
#include "crypto_helper_common.h"
struct TALER_CRYPTO_CsDenominationHelper
{
/**
* Function to call with updates to available key material.
*/
TALER_CRYPTO_CsDenominationKeyStatusCallback dkc;
/**
* Closure for @e dkc
*/
void *dkc_cls;
/**
* Socket address of the denomination helper process.
* Used to reconnect if the connection breaks.
*/
struct sockaddr_un sa;
/**
* The UNIX domain socket, -1 if we are currently not connected.
*/
int sock;
/**
* Have we ever been sync'ed?
*/
bool synced;
};
/**
* Disconnect from the helper process. Updates
* @e sock field in @a dh.
*
* @param[in,out] dh handle to tear down connection of
*/
static void
do_disconnect (struct TALER_CRYPTO_CsDenominationHelper *dh)
{
GNUNET_break (0 == close (dh->sock));
dh->sock = -1;
dh->synced = false;
}
/**
* Try to connect to the helper process. Updates
* @e sock field in @a dh.
*
* @param[in,out] dh handle to establish connection for
* @return #GNUNET_OK on success
*/
static enum GNUNET_GenericReturnValue
try_connect (struct TALER_CRYPTO_CsDenominationHelper *dh)
{
if (-1 != dh->sock)
return GNUNET_OK;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Establishing connection!\n");
dh->sock = socket (AF_UNIX,
SOCK_STREAM,
0);
if (-1 == dh->sock)
{
GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
"socket");
return GNUNET_SYSERR;
}
if (0 !=
connect (dh->sock,
(const struct sockaddr *) &dh->sa,
sizeof (dh->sa)))
{
GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
"connect",
dh->sa.sun_path);
do_disconnect (dh);
return GNUNET_SYSERR;
}
TALER_CRYPTO_helper_cs_poll (dh);
return GNUNET_OK;
}
struct TALER_CRYPTO_CsDenominationHelper *
TALER_CRYPTO_helper_cs_connect (
const struct GNUNET_CONFIGURATION_Handle *cfg,
TALER_CRYPTO_CsDenominationKeyStatusCallback dkc,
void *dkc_cls)
{
struct TALER_CRYPTO_CsDenominationHelper *dh;
char *unixpath;
if (GNUNET_OK !=
GNUNET_CONFIGURATION_get_value_filename (cfg,
"taler-exchange-secmod-cs",
"UNIXPATH",
&unixpath))
{
GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
"taler-exchange-secmod-cs",
"UNIXPATH");
return NULL;
}
/* we use >= here because we want the sun_path to always
be 0-terminated */
if (strlen (unixpath) >= sizeof (dh->sa.sun_path))
{
GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
"taler-exchange-secmod-cs",
"UNIXPATH",
"path too long");
GNUNET_free (unixpath);
return NULL;
}
dh = GNUNET_new (struct TALER_CRYPTO_CsDenominationHelper);
dh->dkc = dkc;
dh->dkc_cls = dkc_cls;
dh->sa.sun_family = AF_UNIX;
strncpy (dh->sa.sun_path,
unixpath,
sizeof (dh->sa.sun_path) - 1);
GNUNET_free (unixpath);
dh->sock = -1;
if (GNUNET_OK !=
try_connect (dh))
{
TALER_CRYPTO_helper_cs_disconnect (dh);
return NULL;
}
return dh;
}
/**
* Handle a #TALER_HELPER_CS_MT_AVAIL message from the helper.
*
* @param dh helper context
* @param hdr message that we received
* @return #GNUNET_OK on success
*/
static enum GNUNET_GenericReturnValue
handle_mt_avail (struct TALER_CRYPTO_CsDenominationHelper *dh,
const struct GNUNET_MessageHeader *hdr)
{
const struct TALER_CRYPTO_CsKeyAvailableNotification *kan
= (const struct TALER_CRYPTO_CsKeyAvailableNotification *) hdr;
const char *buf = (const char *) &kan[1];
const char *section_name;
uint16_t snl;
if (sizeof (*kan) > ntohs (hdr->size))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
snl = ntohs (kan->section_name_len);
if (ntohs (hdr->size) != sizeof (*kan) + snl)
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
if (0 == snl)
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
section_name = buf;
if ('\0' != section_name[snl - 1])
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
{
struct TALER_DenominationPublicKey denom_pub;
struct TALER_CsPubHashP h_cs;
denom_pub.cipher = TALER_DENOMINATION_CS;
denom_pub.details.cs_public_key = kan->denom_pub;
TALER_cs_pub_hash (&denom_pub.details.cs_public_key, &h_cs);
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Received CS key %s (%s)\n",
GNUNET_h2s (&h_cs.hash),
section_name);
if (GNUNET_OK !=
TALER_exchange_secmod_cs_verify (
&h_cs,
section_name,
GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
GNUNET_TIME_relative_ntoh (kan->duration_withdraw),
&kan->secm_pub,
&kan->secm_sig))
{
GNUNET_break_op (0);
TALER_denom_pub_free (&denom_pub);
return GNUNET_SYSERR;
}
dh->dkc (dh->dkc_cls,
section_name,
GNUNET_TIME_timestamp_ntoh (kan->anchor_time),
GNUNET_TIME_relative_ntoh (kan->duration_withdraw),
&h_cs,
&denom_pub,
&kan->secm_pub,
&kan->secm_sig);
TALER_denom_pub_free (&denom_pub);
}
return GNUNET_OK;
}
/**
* Handle a #TALER_HELPER_CS_MT_PURGE message from the helper.
*
* @param dh helper context
* @param hdr message that we received
* @return #GNUNET_OK on success
*/
static enum GNUNET_GenericReturnValue
handle_mt_purge (struct TALER_CRYPTO_CsDenominationHelper *dh,
const struct GNUNET_MessageHeader *hdr)
{
const struct TALER_CRYPTO_CsKeyPurgeNotification *pn
= (const struct TALER_CRYPTO_CsKeyPurgeNotification *) hdr;
if (sizeof (*pn) != ntohs (hdr->size))
{
GNUNET_break_op (0);
return GNUNET_SYSERR;
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Received revocation of denomination key %s\n",
GNUNET_h2s (&pn->h_cs.hash));
dh->dkc (dh->dkc_cls,
NULL,
GNUNET_TIME_UNIT_ZERO_TS,
GNUNET_TIME_UNIT_ZERO,
&pn->h_cs,
NULL,
NULL,
NULL);
return GNUNET_OK;
}
void
TALER_CRYPTO_helper_cs_poll (struct TALER_CRYPTO_CsDenominationHelper *dh)
{
char buf[UINT16_MAX];
size_t off = 0;
unsigned int retry_limit = 3;
const struct GNUNET_MessageHeader *hdr
= (const struct GNUNET_MessageHeader *) buf;
if (GNUNET_OK !=
try_connect (dh))
return; /* give up */
while (1)
{
uint16_t msize;
ssize_t ret;
ret = recv (dh->sock,
buf + off,
sizeof (buf) - off,
(dh->synced && (0 == off))
? MSG_DONTWAIT
: 0);
if (ret < 0)
{
if (EINTR == errno)
continue;
if (EAGAIN == errno)
{
GNUNET_assert (dh->synced);
GNUNET_assert (0 == off);
break;
}
GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
"recv");
do_disconnect (dh);
if (0 == retry_limit)
return; /* give up */
if (GNUNET_OK !=
try_connect (dh))
return; /* give up */
retry_limit--;
continue;
}
if (0 == ret)
{
GNUNET_break (0 == off);
return;
}
off += ret;
more:
if (off < sizeof (struct GNUNET_MessageHeader))
continue;
msize = ntohs (hdr->size);
if (off < msize)
continue;
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Received message of type %u and length %u\n",
(unsigned int) ntohs (hdr->type),
(unsigned int) msize);
switch (ntohs (hdr->type))
{
case TALER_HELPER_CS_MT_AVAIL:
if (GNUNET_OK !=
handle_mt_avail (dh,
hdr))
{
GNUNET_break_op (0);
do_disconnect (dh);
return;
}
break;
case TALER_HELPER_CS_MT_PURGE:
if (GNUNET_OK !=
handle_mt_purge (dh,
hdr))
{
GNUNET_break_op (0);
do_disconnect (dh);
return;
}
break;
case TALER_HELPER_CS_SYNCED:
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Now synchronized with CS helper\n");
dh->synced = true;
break;
default:
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Received unexpected message of type %d (len: %u)\n",
(unsigned int) ntohs (hdr->type),
(unsigned int) msize);
GNUNET_break_op (0);
do_disconnect (dh);
return;
}
memmove (buf,
&buf[msize],
off - msize);
off -= msize;
goto more;
}
}
struct TALER_BlindedDenominationSignature
TALER_CRYPTO_helper_cs_sign (
struct TALER_CRYPTO_CsDenominationHelper *dh,
const struct TALER_CsPubHashP *h_cs,
const struct TALER_BlindedCsPlanchet *blinded_planchet,
enum TALER_ErrorCode *ec)
{
struct TALER_BlindedDenominationSignature ds = {
.cipher = TALER_DENOMINATION_INVALID
};
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Starting signature process\n");
if (GNUNET_OK !=
try_connect (dh))
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to connect to helper\n");
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
return ds;
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Requesting signature\n");
{
char buf[sizeof (struct TALER_CRYPTO_CsSignRequest)];
struct TALER_CRYPTO_CsSignRequest *sr
= (struct TALER_CRYPTO_CsSignRequest *) buf;
sr->header.size = htons (sizeof (buf));
sr->header.type = htons (TALER_HELPER_CS_MT_REQ_SIGN);
sr->reserved = htonl (0);
sr->h_cs = *h_cs;
sr->planchet = *blinded_planchet;
if (GNUNET_OK !=
TALER_crypto_helper_send_all (dh->sock,
buf,
sizeof (buf)))
{
GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
"send");
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
return ds;
}
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Awaiting reply\n");
{
char buf[UINT16_MAX];
size_t off = 0;
const struct GNUNET_MessageHeader *hdr
= (const struct GNUNET_MessageHeader *) buf;
bool finished = false;
*ec = TALER_EC_INVALID;
while (1)
{
uint16_t msize;
ssize_t ret;
ret = recv (dh->sock,
&buf[off],
sizeof (buf) - off,
(finished && (0 == off))
? MSG_DONTWAIT
: 0);
if (ret < 0)
{
if (EINTR == errno)
continue;
if (EAGAIN == errno)
{
GNUNET_assert (finished);
GNUNET_assert (0 == off);
return ds;
}
GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
"recv");
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
break;
}
if (0 == ret)
{
GNUNET_break (0 == off);
if (! finished)
*ec = TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
return ds;
}
off += ret;
more:
if (off < sizeof (struct GNUNET_MessageHeader))
continue;
msize = ntohs (hdr->size);
if (off < msize)
continue;
switch (ntohs (hdr->type))
{
case TALER_HELPER_CS_MT_RES_SIGNATURE:
if (msize < sizeof (struct TALER_CRYPTO_SignResponse))
{
GNUNET_break_op (0);
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
goto end;
}
if (finished)
{
GNUNET_break_op (0);
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
goto end;
}
{
const struct TALER_CRYPTO_SignResponse *sr =
(const struct TALER_CRYPTO_SignResponse *) buf;
// TODO: add nullcheck
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received signature\n");
*ec = TALER_EC_NONE;
finished = true;
ds.cipher = TALER_DENOMINATION_CS;
ds.details.blinded_cs_answer = sr->cs_answer;
break;
}
case TALER_HELPER_CS_MT_RES_SIGN_FAILURE:
if (msize != sizeof (struct TALER_CRYPTO_SignFailure))
{
GNUNET_break_op (0);
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
goto end;
}
{
const struct TALER_CRYPTO_SignFailure *sf =
(const struct TALER_CRYPTO_SignFailure *) buf;
*ec = (enum TALER_ErrorCode) ntohl (sf->ec);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Signing failed!\n");
finished = true;
break;
}
case TALER_HELPER_CS_MT_AVAIL:
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received new key!\n");
if (GNUNET_OK !=
handle_mt_avail (dh,
hdr))
{
GNUNET_break_op (0);
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
goto end;
}
break; /* while(1) loop ensures we recvfrom() again */
case TALER_HELPER_CS_MT_PURGE:
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received revocation!\n");
if (GNUNET_OK !=
handle_mt_purge (dh,
hdr))
{
GNUNET_break_op (0);
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
goto end;
}
break; /* while(1) loop ensures we recvfrom() again */
case TALER_HELPER_CS_SYNCED:
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Synchronized add odd time with CS helper!\n");
dh->synced = true;
break;
default:
GNUNET_break_op (0);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Received unexpected message of type %u\n",
ntohs (hdr->type));
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
goto end;
}
memmove (buf,
&buf[msize],
off - msize);
off -= msize;
goto more;
} /* while(1) */
end:
if (finished)
TALER_blinded_denom_sig_free (&ds);
return ds;
}
}
void
TALER_CRYPTO_helper_cs_revoke (
struct TALER_CRYPTO_CsDenominationHelper *dh,
const struct TALER_CsPubHashP *h_cs)
{
struct TALER_CRYPTO_CsRevokeRequest rr = {
.header.size = htons (sizeof (rr)),
.header.type = htons (TALER_HELPER_CS_MT_REQ_REVOKE),
.h_cs = *h_cs
};
if (GNUNET_OK !=
try_connect (dh))
return; /* give up */
if (GNUNET_OK !=
TALER_crypto_helper_send_all (dh->sock,
&rr,
sizeof (rr)))
{
GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
"send");
do_disconnect (dh);
return;
}
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Requested revocation of denomination key %s\n",
GNUNET_h2s (&h_cs->hash));
}
struct TALER_DenominationCSPublicRPairP
TALER_CRYPTO_helper_cs_r_derive (struct TALER_CRYPTO_CsDenominationHelper *dh,
const struct TALER_CsPubHashP *h_cs,
const struct TALER_CsNonce *nonce,
enum TALER_ErrorCode *ec)
{
struct TALER_DenominationCSPublicRPairP r_pub;
memset (&r_pub,
0,
sizeof (r_pub));
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Starting R derivation process\n");
if (GNUNET_OK !=
try_connect (dh))
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Failed to connect to helper\n");
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
return r_pub;
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Requesting R\n");
{
struct TALER_CRYPTO_CsRDeriveRequest rdr;
rdr.header.size = htons (sizeof (rdr));
rdr.header.type = htons (TALER_HELPER_CS_MT_REQ_RDERIVE);
rdr.reserved = htonl (0);
rdr.h_cs = *h_cs;
rdr.nonce = *nonce;
if (GNUNET_OK !=
TALER_crypto_helper_send_all (dh->sock,
&rdr,
sizeof (rdr)))
{
GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
"send");
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
return r_pub;
}
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Awaiting reply\n");
{
char buf[UINT16_MAX];
size_t off = 0;
const struct GNUNET_MessageHeader *hdr
= (const struct GNUNET_MessageHeader *) buf;
bool finished = false;
*ec = TALER_EC_INVALID;
while (1)
{
uint16_t msize;
ssize_t ret;
ret = recv (dh->sock,
&buf[off],
sizeof (buf) - off,
(finished && (0 == off))
? MSG_DONTWAIT
: 0);
if (ret < 0)
{
if (EINTR == errno)
continue;
if (EAGAIN == errno)
{
GNUNET_assert (finished);
GNUNET_assert (0 == off);
return r_pub;
}
GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
"recv");
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_UNAVAILABLE;
break;
}
if (0 == ret)
{
GNUNET_break (0 == off);
if (! finished)
*ec = TALER_EC_EXCHANGE_SIGNKEY_HELPER_BUG;
return r_pub;
}
off += ret;
more:
if (off < sizeof (struct GNUNET_MessageHeader))
continue;
msize = ntohs (hdr->size);
if (off < msize)
continue;
switch (ntohs (hdr->type))
{
case TALER_HELPER_CS_MT_RES_RDERIVE:
if (msize != sizeof (struct TALER_CRYPTO_RDeriveResponse))
{
GNUNET_break_op (0);
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
goto end;
}
if (finished)
{
GNUNET_break_op (0);
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
goto end;
}
{
const struct TALER_CRYPTO_RDeriveResponse *rdr =
(const struct TALER_CRYPTO_RDeriveResponse *) buf;
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received R\n");
*ec = TALER_EC_NONE;
finished = true;
r_pub = rdr->r_pub;
break;
}
case TALER_HELPER_CS_MT_RES_RDERIVE_FAILURE:
if (msize != sizeof (struct TALER_CRYPTO_RDeriveFailure))
{
GNUNET_break_op (0);
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
goto end;
}
{
const struct TALER_CRYPTO_RDeriveFailure *rdf =
(const struct TALER_CRYPTO_RDeriveFailure *) buf;
*ec = (enum TALER_ErrorCode) ntohl (rdf->ec);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"R derivation failed!\n");
finished = true;
break;
}
case TALER_HELPER_CS_MT_AVAIL:
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received new key!\n");
if (GNUNET_OK !=
handle_mt_avail (dh,
hdr))
{
GNUNET_break_op (0);
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
goto end;
}
break; /* while(1) loop ensures we recvfrom() again */
case TALER_HELPER_CS_MT_PURGE:
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Received revocation!\n");
if (GNUNET_OK !=
handle_mt_purge (dh,
hdr))
{
GNUNET_break_op (0);
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
goto end;
}
break; /* while(1) loop ensures we recvfrom() again */
case TALER_HELPER_CS_SYNCED:
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Synchronized add odd time with CS helper!\n");
dh->synced = true;
break;
default:
GNUNET_break_op (0);
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"Received unexpected message of type %u\n",
ntohs (hdr->type));
do_disconnect (dh);
*ec = TALER_EC_EXCHANGE_DENOMINATION_HELPER_BUG;
goto end;
}
memmove (buf,
&buf[msize],
off - msize);
off -= msize;
goto more;
} /* while(1) */
end:
return r_pub;
}
}
void
TALER_CRYPTO_helper_cs_disconnect (
struct TALER_CRYPTO_CsDenominationHelper *dh)
{
if (-1 != dh->sock)
do_disconnect (dh);
GNUNET_free (dh);
}
/* end of crypto_helper_cs.c */

View File

@ -64,7 +64,7 @@ TALER_exchange_wire_signature_make (
void
TALER_merchant_wire_signature_hash (const char *payto_uri,
const struct TALER_WireSalt *salt,
const struct TALER_WireSaltP *salt,
struct TALER_MerchantWireHash *hc)
{
GNUNET_assert (GNUNET_YES ==
@ -83,7 +83,7 @@ TALER_merchant_wire_signature_hash (const char *payto_uri,
enum GNUNET_GenericReturnValue
TALER_merchant_wire_signature_check (
const char *payto_uri,
const struct TALER_WireSalt *salt,
const struct TALER_WireSaltP *salt,
const struct TALER_MerchantPublicKeyP *merch_pub,
const struct TALER_MerchantSignatureP *merch_sig)
{
@ -105,7 +105,7 @@ TALER_merchant_wire_signature_check (
void
TALER_merchant_wire_signature_make (
const char *payto_uri,
const struct TALER_WireSalt *salt,
const struct TALER_WireSaltP *salt,
const struct TALER_MerchantPrivateKeyP *merch_priv,
struct TALER_MerchantSignatureP *merch_sig)
{

View File

@ -34,6 +34,7 @@ TALER_denom_priv_create (struct TALER_DenominationPrivateKey *denom_priv,
memset (denom_pub,
0,
sizeof (*denom_pub));
switch (cipher)
{
case TALER_DENOMINATION_INVALID:
@ -63,10 +64,17 @@ TALER_denom_priv_create (struct TALER_DenominationPrivateKey *denom_priv,
denom_pub->details.rsa_public_key
= GNUNET_CRYPTO_rsa_private_key_get_public (
denom_priv->details.rsa_private_key);
denom_priv->cipher = cipher;
denom_pub->cipher = cipher;
denom_priv->cipher = TALER_DENOMINATION_RSA;
denom_pub->cipher = TALER_DENOMINATION_RSA;
return GNUNET_OK;
case TALER_DENOMINATION_CS:
GNUNET_CRYPTO_cs_private_key_generate (&denom_priv->details.cs_private_key);
GNUNET_CRYPTO_cs_private_key_get_public (
&denom_priv->details.cs_private_key,
&denom_pub->details.cs_public_key);
denom_priv->cipher = TALER_DENOMINATION_CS;
denom_pub->cipher = TALER_DENOMINATION_CS;
return GNUNET_OK;
// TODO: add case for Clause-Schnorr
default:
GNUNET_break (0);
}
@ -74,15 +82,43 @@ TALER_denom_priv_create (struct TALER_DenominationPrivateKey *denom_priv,
}
enum GNUNET_GenericReturnValue
TALER_denom_cs_derive_r_public (const struct TALER_CsNonce *nonce,
const struct
TALER_DenominationPrivateKey *denom_priv,
struct TALER_DenominationCSPublicRPairP *r_pub)
{
if (denom_priv->cipher != TALER_DENOMINATION_CS)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
struct GNUNET_CRYPTO_CsRSecret r[2];
GNUNET_CRYPTO_cs_r_derive (&nonce->nonce,
&denom_priv->details.cs_private_key,
r);
GNUNET_CRYPTO_cs_r_get_public (&r[0], &r_pub->r_pub[0]);
GNUNET_CRYPTO_cs_r_get_public (&r[1], &r_pub->r_pub[1]);
return GNUNET_OK;
}
enum GNUNET_GenericReturnValue
TALER_denom_sign_blinded (struct TALER_BlindedDenominationSignature *denom_sig,
const struct TALER_DenominationPrivateKey *denom_priv,
void *blinded_msg,
size_t blinded_msg_size)
const struct TALER_BlindedPlanchet *blinded_planchet)
{
memset (denom_sig,
0,
sizeof (*denom_sig));
if (blinded_planchet->cipher != denom_priv->cipher)
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
switch (denom_priv->cipher)
{
case TALER_DENOMINATION_INVALID:
@ -92,8 +128,8 @@ TALER_denom_sign_blinded (struct TALER_BlindedDenominationSignature *denom_sig,
denom_sig->details.blinded_rsa_signature
= GNUNET_CRYPTO_rsa_sign_blinded (
denom_priv->details.rsa_private_key,
blinded_msg,
blinded_msg_size);
blinded_planchet->details.rsa_blinded_planchet.blinded_msg,
blinded_planchet->details.rsa_blinded_planchet.blinded_msg_size);
if (NULL == denom_sig->details.blinded_rsa_signature)
{
GNUNET_break (0);
@ -101,7 +137,27 @@ TALER_denom_sign_blinded (struct TALER_BlindedDenominationSignature *denom_sig,
}
denom_sig->cipher = TALER_DENOMINATION_RSA;
return GNUNET_OK;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
{
struct GNUNET_CRYPTO_CsRSecret r[2];
GNUNET_CRYPTO_cs_r_derive (
&blinded_planchet->details.cs_blinded_planchet.nonce.nonce,
&denom_priv->details.cs_private_key,
r);
denom_sig->details.blinded_cs_answer.b =
GNUNET_CRYPTO_cs_sign_derive (&denom_priv->details.cs_private_key,
r,
blinded_planchet->details.
cs_blinded_planchet.c,
&blinded_planchet->details.
cs_blinded_planchet.nonce.nonce,
&denom_sig->details.blinded_cs_answer.
s_scalar);
denom_sig->cipher = TALER_DENOMINATION_CS;
}
return GNUNET_OK;
default:
GNUNET_break (0);
}
@ -139,7 +195,17 @@ TALER_denom_sig_unblind (
}
denom_sig->cipher = TALER_DENOMINATION_RSA;
return GNUNET_OK;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
{
struct GNUNET_CRYPTO_CsBlindingSecret bs[2];
GNUNET_CRYPTO_cs_blinding_secrets_derive (&bks->nonce, bs);
GNUNET_CRYPTO_cs_unblind (&bdenom_sig->details.blinded_cs_answer.s_scalar,
&bs[bdenom_sig->details.blinded_cs_answer.b],
&denom_sig->details.cs_signature.s_scalar);
denom_sig->cipher = TALER_DENOMINATION_CS;
return GNUNET_OK;
}
default:
GNUNET_break (0);
}
@ -147,15 +213,6 @@ TALER_denom_sig_unblind (
}
void
TALER_blinding_secret_create (union TALER_DenominationBlindingKeyP *bs)
{
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
bs,
sizeof (*bs));
}
/**
* Hash @a rsa.
*
@ -172,6 +229,22 @@ TALER_rsa_pub_hash (const struct GNUNET_CRYPTO_RsaPublicKey *rsa,
}
/**
* Hash @a cs. key
*
* @param cs key to hash
* @param[out] h_cs where to write the result
*/
void
TALER_cs_pub_hash (const struct GNUNET_CRYPTO_CsPublicKey *cs,
struct TALER_CsPubHashP *h_cs)
{
GNUNET_CRYPTO_hash (cs,
sizeof(*cs),
&h_cs->hash);
}
void
TALER_denom_pub_hash (const struct TALER_DenominationPublicKey *denom_pub,
struct TALER_DenominationHash *denom_hash)
@ -202,7 +275,11 @@ TALER_denom_pub_hash (const struct TALER_DenominationPublicKey *denom_pub,
GNUNET_free (buf);
}
break;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
GNUNET_CRYPTO_hash_context_read (hc,
&denom_pub->details.cs_public_key,
sizeof(denom_pub->details.cs_public_key));
break;
default:
GNUNET_assert (0);
}
@ -225,7 +302,13 @@ TALER_denom_priv_to_pub (const struct TALER_DenominationPrivateKey *denom_priv,
= GNUNET_CRYPTO_rsa_private_key_get_public (
denom_priv->details.rsa_private_key);
return;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
denom_pub->cipher = TALER_DENOMINATION_CS;
denom_pub->age_mask = age_mask;
GNUNET_CRYPTO_cs_private_key_get_public (
&denom_priv->details.cs_private_key,
&denom_pub->details.cs_public_key);
return;
default:
GNUNET_assert (0);
}
@ -233,32 +316,55 @@ TALER_denom_priv_to_pub (const struct TALER_DenominationPrivateKey *denom_priv,
enum GNUNET_GenericReturnValue
TALER_denom_blind (const struct TALER_DenominationPublicKey *dk,
TALER_denom_blind (
const struct TALER_DenominationPublicKey *dk,
const union TALER_DenominationBlindingKeyP *coin_bks,
const struct TALER_AgeHash *age_commitment_hash,
const struct TALER_CoinSpendPublicKeyP *coin_pub,
const struct TALER_ExchangeWithdrawValues *alg_values,
struct TALER_CoinPubHash *c_hash,
void **coin_ev,
size_t *coin_ev_size)
struct TALER_BlindedPlanchet *blinded_planchet)
{
switch (dk->cipher)
{
case TALER_DENOMINATION_RSA:
TALER_coin_pub_hash (coin_pub,
age_commitment_hash,
c_hash);
switch (dk->cipher)
{
case TALER_DENOMINATION_RSA:
blinded_planchet->cipher = dk->cipher;
if (GNUNET_YES !=
GNUNET_CRYPTO_rsa_blind (&c_hash->hash,
&coin_bks->rsa_bks,
dk->details.rsa_public_key,
coin_ev,
coin_ev_size))
&blinded_planchet->details.rsa_blinded_planchet
.blinded_msg,
&blinded_planchet->details.rsa_blinded_planchet
.blinded_msg_size))
{
GNUNET_break (0);
return GNUNET_SYSERR;
}
return GNUNET_OK;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
{
blinded_planchet->cipher = dk->cipher;
struct TALER_DenominationCSPublicRPairP blinded_r_pub;
struct GNUNET_CRYPTO_CsBlindingSecret bs[2];
GNUNET_CRYPTO_cs_blinding_secrets_derive (&coin_bks->nonce,
bs);
GNUNET_CRYPTO_cs_calc_blinded_c (
bs,
alg_values->details.cs_values.r_pub_pair.r_pub,
&dk->details.cs_public_key,
&c_hash->hash,
sizeof(struct GNUNET_HashCode),
blinded_planchet->details.
cs_blinded_planchet.c,
blinded_r_pub.r_pub);
return GNUNET_OK;
}
default:
GNUNET_break (0);
return GNUNET_SYSERR;
@ -276,6 +382,7 @@ TALER_denom_pub_verify (const struct TALER_DenominationPublicKey *denom_pub,
GNUNET_break (0);
return GNUNET_SYSERR;
}
switch (denom_pub->cipher)
{
case TALER_DENOMINATION_INVALID:
@ -292,7 +399,18 @@ TALER_denom_pub_verify (const struct TALER_DenominationPublicKey *denom_pub,
return GNUNET_NO;
}
return GNUNET_YES;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
if (GNUNET_OK !=
GNUNET_CRYPTO_cs_verify (&denom_sig->details.cs_signature,
&denom_pub->details.cs_public_key,
&c_hash->hash,
sizeof(struct GNUNET_HashCode)))
{
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
"Coin signature is invalid\n");
return GNUNET_NO;
}
return GNUNET_YES;
default:
GNUNET_assert (0);
}
@ -314,7 +432,9 @@ TALER_denom_pub_free (struct TALER_DenominationPublicKey *denom_pub)
}
denom_pub->cipher = TALER_DENOMINATION_INVALID;
return;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
// ATM nothing needs to be freed, but check again after implementation.
return;
default:
GNUNET_assert (0);
}
@ -336,7 +456,9 @@ TALER_denom_priv_free (struct TALER_DenominationPrivateKey *denom_priv)
}
denom_priv->cipher = TALER_DENOMINATION_INVALID;
return;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
// ATM nothing needs to be freed, but check again after implementation.
return;
default:
GNUNET_assert (0);
}
@ -358,7 +480,9 @@ TALER_denom_sig_free (struct TALER_DenominationSignature *denom_sig)
}
denom_sig->cipher = TALER_DENOMINATION_INVALID;
return;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
// ATM nothing needs to be freed, but check again after implementation.
return;
default:
GNUNET_assert (0);
}
@ -382,7 +506,9 @@ TALER_blinded_denom_sig_free (
}
denom_sig->cipher = TALER_DENOMINATION_INVALID;
return;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
// ATM nothing needs to be freed, but check again after implementation.
return;
default:
GNUNET_assert (0);
}
@ -408,7 +534,9 @@ TALER_denom_pub_deep_copy (struct TALER_DenominationPublicKey *denom_dst,
= GNUNET_CRYPTO_rsa_public_key_dup (
denom_src->details.rsa_public_key);
return;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
// In Case of CS, the above is already a deep copy *denom_dst = *denom_src;
return;
default:
GNUNET_assert (0);
}
@ -429,7 +557,9 @@ TALER_denom_sig_deep_copy (struct TALER_DenominationSignature *denom_dst,
= GNUNET_CRYPTO_rsa_signature_dup (
denom_src->details.rsa_signature);
return;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
// In Case of CS, the above is already a deep copy *denom_dst = *denom_src;
return;
default:
GNUNET_assert (0);
}
@ -451,7 +581,9 @@ TALER_blinded_denom_sig_deep_copy (
= GNUNET_CRYPTO_rsa_signature_dup (
denom_src->details.blinded_rsa_signature);
return;
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
// In Case of CS, the above is already a deep copy *denom_dst = *denom_src;
return;
default:
GNUNET_assert (0);
}
@ -473,7 +605,9 @@ TALER_denom_pub_cmp (const struct TALER_DenominationPublicKey *denom1,
case TALER_DENOMINATION_RSA:
return GNUNET_CRYPTO_rsa_public_key_cmp (denom1->details.rsa_public_key,
denom2->details.rsa_public_key);
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
return GNUNET_memcmp (&denom1->details.cs_public_key,
&denom2->details.cs_public_key);
default:
GNUNET_assert (0);
}
@ -494,7 +628,38 @@ TALER_denom_sig_cmp (const struct TALER_DenominationSignature *sig1,
case TALER_DENOMINATION_RSA:
return GNUNET_CRYPTO_rsa_signature_cmp (sig1->details.rsa_signature,
sig2->details.rsa_signature);
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
return GNUNET_memcmp (&sig1->details.cs_signature,
&sig2->details.cs_signature);
default:
GNUNET_assert (0);
}
return -2;
}
int
TALER_blinded_planchet_cmp (
const struct TALER_BlindedPlanchet *bp1,
const struct TALER_BlindedPlanchet *bp2)
{
if (bp1->cipher != bp2->cipher)
return (bp1->cipher > bp2->cipher) ? 1 : -1;
switch (bp1->cipher)
{
case TALER_DENOMINATION_INVALID:
return 0;
case TALER_DENOMINATION_RSA:
if (bp1->details.rsa_blinded_planchet.blinded_msg_size !=
bp2->details.rsa_blinded_planchet.blinded_msg_size)
return (bp1->details.rsa_blinded_planchet.blinded_msg_size >
bp2->details.rsa_blinded_planchet.blinded_msg_size) ? 1 : -1;
return memcmp (bp1->details.rsa_blinded_planchet.blinded_msg,
bp2->details.rsa_blinded_planchet.blinded_msg,
bp1->details.rsa_blinded_planchet.blinded_msg_size);
case TALER_DENOMINATION_CS:
return GNUNET_memcmp (&bp1->details.cs_blinded_planchet,
&bp2->details.cs_blinded_planchet);
default:
GNUNET_assert (0);
}
@ -516,7 +681,9 @@ TALER_blinded_denom_sig_cmp (
case TALER_DENOMINATION_RSA:
return GNUNET_CRYPTO_rsa_signature_cmp (sig1->details.blinded_rsa_signature,
sig2->details.blinded_rsa_signature);
// TODO: add case for Clause-Schnorr
case TALER_DENOMINATION_CS:
return GNUNET_memcmp (&sig1->details.blinded_cs_answer,
&sig2->details.blinded_cs_answer);
default:
GNUNET_assert (0);
}
@ -524,4 +691,36 @@ TALER_blinded_denom_sig_cmp (
}
void
TALER_blinded_planchet_hash (const struct TALER_BlindedPlanchet *bp,
struct GNUNET_HashContext *hash_context)
{
uint32_t cipher = htonl (bp->cipher);
GNUNET_CRYPTO_hash_context_read (hash_context,
&cipher,
sizeof (cipher));
switch (bp->cipher)
{
case TALER_DENOMINATION_INVALID:
break;
case TALER_DENOMINATION_RSA:
GNUNET_CRYPTO_hash_context_read (
hash_context,
bp->details.rsa_blinded_planchet.blinded_msg,
bp->details.rsa_blinded_planchet.blinded_msg_size);
break;
case TALER_DENOMINATION_CS:
GNUNET_CRYPTO_hash_context_read (
hash_context,
&bp->details.cs_blinded_planchet,
sizeof (bp->details.cs_blinded_planchet));
break;
default:
GNUNET_assert (0);
break;
}
}
/* end of denom.c */

View File

@ -81,7 +81,7 @@ TALER_exchange_secmod_rsa_sign (
struct TALER_DenominationKeyAnnouncementPS dka = {
.purpose.purpose = htonl (TALER_SIGNATURE_SM_RSA_DENOMINATION_KEY),
.purpose.size = htonl (sizeof (dka)),
.h_rsa = *h_rsa,
.h_denom.hash = h_rsa->hash,
.anchor_time = GNUNET_TIME_timestamp_hton (start_sign),
.duration_withdraw = GNUNET_TIME_relative_hton (duration)
};
@ -108,7 +108,7 @@ TALER_exchange_secmod_rsa_verify (
struct TALER_DenominationKeyAnnouncementPS dka = {
.purpose.purpose = htonl (TALER_SIGNATURE_SM_RSA_DENOMINATION_KEY),
.purpose.size = htonl (sizeof (dka)),
.h_rsa = *h_rsa,
.h_denom.hash = h_rsa->hash,
.anchor_time = GNUNET_TIME_timestamp_hton (start_sign),
.duration_withdraw = GNUNET_TIME_relative_hton (duration)
};
@ -124,4 +124,59 @@ TALER_exchange_secmod_rsa_verify (
}
void
TALER_exchange_secmod_cs_sign (
const struct TALER_CsPubHashP *h_cs,
const char *section_name,
struct GNUNET_TIME_Timestamp start_sign,
struct GNUNET_TIME_Relative duration,
const struct TALER_SecurityModulePrivateKeyP *secm_priv,
struct TALER_SecurityModuleSignatureP *secm_sig)
{
struct TALER_DenominationKeyAnnouncementPS dka = {
.purpose.purpose = htonl (TALER_SIGNATURE_SM_CS_DENOMINATION_KEY),
.purpose.size = htonl (sizeof (dka)),
.h_denom.hash = h_cs->hash,
.anchor_time = GNUNET_TIME_timestamp_hton (start_sign),
.duration_withdraw = GNUNET_TIME_relative_hton (duration)
};
GNUNET_CRYPTO_hash (section_name,
strlen (section_name) + 1,
&dka.h_section_name);
GNUNET_CRYPTO_eddsa_sign (&secm_priv->eddsa_priv,
&dka,
&secm_sig->eddsa_signature);
}
enum GNUNET_GenericReturnValue
TALER_exchange_secmod_cs_verify (
const struct TALER_CsPubHashP *h_cs,
const char *section_name,
struct GNUNET_TIME_Timestamp start_sign,
struct GNUNET_TIME_Relative duration,
const struct TALER_SecurityModulePublicKeyP *secm_pub,
const struct TALER_SecurityModuleSignatureP *secm_sig)
{
struct TALER_DenominationKeyAnnouncementPS dka = {
.purpose.purpose = htonl (TALER_SIGNATURE_SM_CS_DENOMINATION_KEY),
.purpose.size = htonl (sizeof (dka)),
.h_denom.hash = h_cs->hash,
.anchor_time = GNUNET_TIME_timestamp_hton (start_sign),
.duration_withdraw = GNUNET_TIME_relative_hton (duration)
};
GNUNET_CRYPTO_hash (section_name,
strlen (section_name) + 1,
&dka.h_section_name);
return
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_SM_CS_DENOMINATION_KEY,
&dka,
&secm_sig->eddsa_signature,
&secm_pub->eddsa_pub);
}
/* end of secmod_signatures.c */

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More