-initial import for mint
This commit is contained in:
commit
57d1f08dbc
26
.gitignore
vendored
Normal file
26
.gitignore
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
*~
|
||||
*Makefile.in
|
||||
*Makefile
|
||||
aclocal.m4
|
||||
autom4te.cache
|
||||
autoscan.log
|
||||
compile
|
||||
configure
|
||||
depcomp
|
||||
missing
|
||||
taler_config.h.in
|
||||
install-sh
|
||||
config.log
|
||||
config.status
|
||||
stamp-h1
|
||||
taler_config.h
|
||||
config.guess
|
||||
config.sub
|
||||
libtool
|
||||
ltmain.sh
|
||||
test-driver
|
||||
m4/
|
||||
GPATH
|
||||
GRTAGS
|
||||
GTAGS
|
||||
*.swp
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "doc/api"]
|
||||
path = doc/api
|
||||
url = git@git.taler.net:api
|
4
AUTHORS
Normal file
4
AUTHORS
Normal file
@ -0,0 +1,4 @@
|
||||
Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||
Florian Dold
|
||||
Christian Grothoff <christian@grothoff.org>
|
||||
Benedikt Mueller
|
661
COPYING
Normal file
661
COPYING
Normal file
@ -0,0 +1,661 @@
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program 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 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
370
INSTALL
Normal file
370
INSTALL
Normal file
@ -0,0 +1,370 @@
|
||||
Installation Instructions
|
||||
*************************
|
||||
|
||||
Copyright (C) 1994-1996, 1999-2002, 2004-2013 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. This file is offered as-is,
|
||||
without warranty of any kind.
|
||||
|
||||
Basic Installation
|
||||
==================
|
||||
|
||||
Briefly, the shell command `./configure && make && make install'
|
||||
should configure, build, and install this package. The following
|
||||
more-detailed instructions are generic; see the `README' file for
|
||||
instructions specific to this package. Some packages provide this
|
||||
`INSTALL' file but do not implement all of the features documented
|
||||
below. The lack of an optional feature in a given package is not
|
||||
necessarily a bug. More recommendations for GNU packages can be found
|
||||
in *note Makefile Conventions: (standards)Makefile Conventions.
|
||||
|
||||
The `configure' shell script attempts to guess correct values for
|
||||
various system-dependent variables used during compilation. It uses
|
||||
those values to create a `Makefile' in each directory of the package.
|
||||
It may also create one or more `.h' files containing system-dependent
|
||||
definitions. Finally, it creates a shell script `config.status' that
|
||||
you can run in the future to recreate the current configuration, and a
|
||||
file `config.log' containing compiler output (useful mainly for
|
||||
debugging `configure').
|
||||
|
||||
It can also use an optional file (typically called `config.cache'
|
||||
and enabled with `--cache-file=config.cache' or simply `-C') that saves
|
||||
the results of its tests to speed up reconfiguring. Caching is
|
||||
disabled by default to prevent problems with accidental use of stale
|
||||
cache files.
|
||||
|
||||
If you need to do unusual things to compile the package, please try
|
||||
to figure out how `configure' could check whether to do them, and mail
|
||||
diffs or instructions to the address given in the `README' so they can
|
||||
be considered for the next release. If you are using the cache, and at
|
||||
some point `config.cache' contains results you don't want to keep, you
|
||||
may remove or edit it.
|
||||
|
||||
The file `configure.ac' (or `configure.in') is used to create
|
||||
`configure' by a program called `autoconf'. You need `configure.ac' if
|
||||
you want to change it or regenerate `configure' using a newer version
|
||||
of `autoconf'.
|
||||
|
||||
The simplest way to compile this package is:
|
||||
|
||||
1. `cd' to the directory containing the package's source code and type
|
||||
`./configure' to configure the package for your system.
|
||||
|
||||
Running `configure' might take a while. While running, it prints
|
||||
some messages telling which features it is checking for.
|
||||
|
||||
2. Type `make' to compile the package.
|
||||
|
||||
3. Optionally, type `make check' to run any self-tests that come with
|
||||
the package, generally using the just-built uninstalled binaries.
|
||||
|
||||
4. Type `make install' to install the programs and any data files and
|
||||
documentation. When installing into a prefix owned by root, it is
|
||||
recommended that the package be configured and built as a regular
|
||||
user, and only the `make install' phase executed with root
|
||||
privileges.
|
||||
|
||||
5. Optionally, type `make installcheck' to repeat any self-tests, but
|
||||
this time using the binaries in their final installed location.
|
||||
This target does not install anything. Running this target as a
|
||||
regular user, particularly if the prior `make install' required
|
||||
root privileges, verifies that the installation completed
|
||||
correctly.
|
||||
|
||||
6. You can remove the program binaries and object files from the
|
||||
source code directory by typing `make clean'. To also remove the
|
||||
files that `configure' created (so you can compile the package for
|
||||
a different kind of computer), type `make distclean'. There is
|
||||
also a `make maintainer-clean' target, but that is intended mainly
|
||||
for the package's developers. If you use it, you may have to get
|
||||
all sorts of other programs in order to regenerate files that came
|
||||
with the distribution.
|
||||
|
||||
7. Often, you can also type `make uninstall' to remove the installed
|
||||
files again. In practice, not all packages have tested that
|
||||
uninstallation works correctly, even though it is required by the
|
||||
GNU Coding Standards.
|
||||
|
||||
8. Some packages, particularly those that use Automake, provide `make
|
||||
distcheck', which can by used by developers to test that all other
|
||||
targets like `make install' and `make uninstall' work correctly.
|
||||
This target is generally not run by end users.
|
||||
|
||||
Compilers and Options
|
||||
=====================
|
||||
|
||||
Some systems require unusual options for compilation or linking that
|
||||
the `configure' script does not know about. Run `./configure --help'
|
||||
for details on some of the pertinent environment variables.
|
||||
|
||||
You can give `configure' initial values for configuration parameters
|
||||
by setting variables in the command line or in the environment. Here
|
||||
is an example:
|
||||
|
||||
./configure CC=c99 CFLAGS=-g LIBS=-lposix
|
||||
|
||||
*Note Defining Variables::, for more details.
|
||||
|
||||
Compiling For Multiple Architectures
|
||||
====================================
|
||||
|
||||
You can compile the package for more than one kind of computer at the
|
||||
same time, by placing the object files for each architecture in their
|
||||
own directory. To do this, you can use GNU `make'. `cd' to the
|
||||
directory where you want the object files and executables to go and run
|
||||
the `configure' script. `configure' automatically checks for the
|
||||
source code in the directory that `configure' is in and in `..'. This
|
||||
is known as a "VPATH" build.
|
||||
|
||||
With a non-GNU `make', it is safer to compile the package for one
|
||||
architecture at a time in the source code directory. After you have
|
||||
installed the package for one architecture, use `make distclean' before
|
||||
reconfiguring for another architecture.
|
||||
|
||||
On MacOS X 10.5 and later systems, you can create libraries and
|
||||
executables that work on multiple system types--known as "fat" or
|
||||
"universal" binaries--by specifying multiple `-arch' options to the
|
||||
compiler but only a single `-arch' option to the preprocessor. Like
|
||||
this:
|
||||
|
||||
./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
||||
CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
|
||||
CPP="gcc -E" CXXCPP="g++ -E"
|
||||
|
||||
This is not guaranteed to produce working output in all cases, you
|
||||
may have to build one architecture at a time and combine the results
|
||||
using the `lipo' tool if you have problems.
|
||||
|
||||
Installation Names
|
||||
==================
|
||||
|
||||
By default, `make install' installs the package's commands under
|
||||
`/usr/local/bin', include files under `/usr/local/include', etc. You
|
||||
can specify an installation prefix other than `/usr/local' by giving
|
||||
`configure' the option `--prefix=PREFIX', where PREFIX must be an
|
||||
absolute file name.
|
||||
|
||||
You can specify separate installation prefixes for
|
||||
architecture-specific files and architecture-independent files. If you
|
||||
pass the option `--exec-prefix=PREFIX' to `configure', the package uses
|
||||
PREFIX as the prefix for installing programs and libraries.
|
||||
Documentation and other data files still use the regular prefix.
|
||||
|
||||
In addition, if you use an unusual directory layout you can give
|
||||
options like `--bindir=DIR' to specify different values for particular
|
||||
kinds of files. Run `configure --help' for a list of the directories
|
||||
you can set and what kinds of files go in them. In general, the
|
||||
default for these options is expressed in terms of `${prefix}', so that
|
||||
specifying just `--prefix' will affect all of the other directory
|
||||
specifications that were not explicitly provided.
|
||||
|
||||
The most portable way to affect installation locations is to pass the
|
||||
correct locations to `configure'; however, many packages provide one or
|
||||
both of the following shortcuts of passing variable assignments to the
|
||||
`make install' command line to change installation locations without
|
||||
having to reconfigure or recompile.
|
||||
|
||||
The first method involves providing an override variable for each
|
||||
affected directory. For example, `make install
|
||||
prefix=/alternate/directory' will choose an alternate location for all
|
||||
directory configuration variables that were expressed in terms of
|
||||
`${prefix}'. Any directories that were specified during `configure',
|
||||
but not in terms of `${prefix}', must each be overridden at install
|
||||
time for the entire installation to be relocated. The approach of
|
||||
makefile variable overrides for each directory variable is required by
|
||||
the GNU Coding Standards, and ideally causes no recompilation.
|
||||
However, some platforms have known limitations with the semantics of
|
||||
shared libraries that end up requiring recompilation when using this
|
||||
method, particularly noticeable in packages that use GNU Libtool.
|
||||
|
||||
The second method involves providing the `DESTDIR' variable. For
|
||||
example, `make install DESTDIR=/alternate/directory' will prepend
|
||||
`/alternate/directory' before all installation names. The approach of
|
||||
`DESTDIR' overrides is not required by the GNU Coding Standards, and
|
||||
does not work on platforms that have drive letters. On the other hand,
|
||||
it does better at avoiding recompilation issues, and works well even
|
||||
when some directory options were not specified in terms of `${prefix}'
|
||||
at `configure' time.
|
||||
|
||||
Optional Features
|
||||
=================
|
||||
|
||||
If the package supports it, you can cause programs to be installed
|
||||
with an extra prefix or suffix on their names by giving `configure' the
|
||||
option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
|
||||
|
||||
Some packages pay attention to `--enable-FEATURE' options to
|
||||
`configure', where FEATURE indicates an optional part of the package.
|
||||
They may also pay attention to `--with-PACKAGE' options, where PACKAGE
|
||||
is something like `gnu-as' or `x' (for the X Window System). The
|
||||
`README' should mention any `--enable-' and `--with-' options that the
|
||||
package recognizes.
|
||||
|
||||
For packages that use the X Window System, `configure' can usually
|
||||
find the X include and library files automatically, but if it doesn't,
|
||||
you can use the `configure' options `--x-includes=DIR' and
|
||||
`--x-libraries=DIR' to specify their locations.
|
||||
|
||||
Some packages offer the ability to configure how verbose the
|
||||
execution of `make' will be. For these packages, running `./configure
|
||||
--enable-silent-rules' sets the default to minimal output, which can be
|
||||
overridden with `make V=1'; while running `./configure
|
||||
--disable-silent-rules' sets the default to verbose, which can be
|
||||
overridden with `make V=0'.
|
||||
|
||||
Particular systems
|
||||
==================
|
||||
|
||||
On HP-UX, the default C compiler is not ANSI C compatible. If GNU
|
||||
CC is not installed, it is recommended to use the following options in
|
||||
order to use an ANSI C compiler:
|
||||
|
||||
./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
|
||||
|
||||
and if that doesn't work, install pre-built binaries of GCC for HP-UX.
|
||||
|
||||
HP-UX `make' updates targets which have the same time stamps as
|
||||
their prerequisites, which makes it generally unusable when shipped
|
||||
generated files such as `configure' are involved. Use GNU `make'
|
||||
instead.
|
||||
|
||||
On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
|
||||
parse its `<wchar.h>' header file. The option `-nodtk' can be used as
|
||||
a workaround. If GNU CC is not installed, it is therefore recommended
|
||||
to try
|
||||
|
||||
./configure CC="cc"
|
||||
|
||||
and if that doesn't work, try
|
||||
|
||||
./configure CC="cc -nodtk"
|
||||
|
||||
On Solaris, don't put `/usr/ucb' early in your `PATH'. This
|
||||
directory contains several dysfunctional programs; working variants of
|
||||
these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
|
||||
in your `PATH', put it _after_ `/usr/bin'.
|
||||
|
||||
On Haiku, software installed for all users goes in `/boot/common',
|
||||
not `/usr/local'. It is recommended to use the following options:
|
||||
|
||||
./configure --prefix=/boot/common
|
||||
|
||||
Specifying the System Type
|
||||
==========================
|
||||
|
||||
There may be some features `configure' cannot figure out
|
||||
automatically, but needs to determine by the type of machine the package
|
||||
will run on. Usually, assuming the package is built to be run on the
|
||||
_same_ architectures, `configure' can figure that out, but if it prints
|
||||
a message saying it cannot guess the machine type, give it the
|
||||
`--build=TYPE' option. TYPE can either be a short name for the system
|
||||
type, such as `sun4', or a canonical name which has the form:
|
||||
|
||||
CPU-COMPANY-SYSTEM
|
||||
|
||||
where SYSTEM can have one of these forms:
|
||||
|
||||
OS
|
||||
KERNEL-OS
|
||||
|
||||
See the file `config.sub' for the possible values of each field. If
|
||||
`config.sub' isn't included in this package, then this package doesn't
|
||||
need to know the machine type.
|
||||
|
||||
If you are _building_ compiler tools for cross-compiling, you should
|
||||
use the option `--target=TYPE' to select the type of system they will
|
||||
produce code for.
|
||||
|
||||
If you want to _use_ a cross compiler, that generates code for a
|
||||
platform different from the build platform, you should specify the
|
||||
"host" platform (i.e., that on which the generated programs will
|
||||
eventually be run) with `--host=TYPE'.
|
||||
|
||||
Sharing Defaults
|
||||
================
|
||||
|
||||
If you want to set default values for `configure' scripts to share,
|
||||
you can create a site shell script called `config.site' that gives
|
||||
default values for variables like `CC', `cache_file', and `prefix'.
|
||||
`configure' looks for `PREFIX/share/config.site' if it exists, then
|
||||
`PREFIX/etc/config.site' if it exists. Or, you can set the
|
||||
`CONFIG_SITE' environment variable to the location of the site script.
|
||||
A warning: not all `configure' scripts look for a site script.
|
||||
|
||||
Defining Variables
|
||||
==================
|
||||
|
||||
Variables not defined in a site shell script can be set in the
|
||||
environment passed to `configure'. However, some packages may run
|
||||
configure again during the build, and the customized values of these
|
||||
variables may be lost. In order to avoid this problem, you should set
|
||||
them in the `configure' command line, using `VAR=value'. For example:
|
||||
|
||||
./configure CC=/usr/local2/bin/gcc
|
||||
|
||||
causes the specified `gcc' to be used as the C compiler (unless it is
|
||||
overridden in the site shell script).
|
||||
|
||||
Unfortunately, this technique does not work for `CONFIG_SHELL' due to
|
||||
an Autoconf limitation. Until the limitation is lifted, you can use
|
||||
this workaround:
|
||||
|
||||
CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash
|
||||
|
||||
`configure' Invocation
|
||||
======================
|
||||
|
||||
`configure' recognizes the following options to control how it
|
||||
operates.
|
||||
|
||||
`--help'
|
||||
`-h'
|
||||
Print a summary of all of the options to `configure', and exit.
|
||||
|
||||
`--help=short'
|
||||
`--help=recursive'
|
||||
Print a summary of the options unique to this package's
|
||||
`configure', and exit. The `short' variant lists options used
|
||||
only in the top level, while the `recursive' variant lists options
|
||||
also present in any nested packages.
|
||||
|
||||
`--version'
|
||||
`-V'
|
||||
Print the version of Autoconf used to generate the `configure'
|
||||
script, and exit.
|
||||
|
||||
`--cache-file=FILE'
|
||||
Enable the cache: use and save the results of the tests in FILE,
|
||||
traditionally `config.cache'. FILE defaults to `/dev/null' to
|
||||
disable caching.
|
||||
|
||||
`--config-cache'
|
||||
`-C'
|
||||
Alias for `--cache-file=config.cache'.
|
||||
|
||||
`--quiet'
|
||||
`--silent'
|
||||
`-q'
|
||||
Do not print messages saying which checks are being made. To
|
||||
suppress all normal output, redirect it to `/dev/null' (any error
|
||||
messages will still be shown).
|
||||
|
||||
`--srcdir=DIR'
|
||||
Look for the package's source code in directory DIR. Usually
|
||||
`configure' can determine that directory automatically.
|
||||
|
||||
`--prefix=DIR'
|
||||
Use DIR as the installation prefix. *note Installation Names::
|
||||
for more details, including other options available for fine-tuning
|
||||
the installation locations.
|
||||
|
||||
`--no-create'
|
||||
`-n'
|
||||
Run the configure checks, but stop before creating any output
|
||||
files.
|
||||
|
||||
`configure' also accepts some other, not widely useful, options. Run
|
||||
`configure --help' for more details.
|
3
Makefile.am
Normal file
3
Makefile.am
Normal file
@ -0,0 +1,3 @@
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src/include
|
||||
SUBDIRS = src doc
|
||||
ACLOCAL_AMFLAGS = -I m4
|
156
configure.ac
Normal file
156
configure.ac
Normal file
@ -0,0 +1,156 @@
|
||||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ([2.69])
|
||||
AC_INIT([taler-mint], [0.0.0], [taler-bug@gnunet.org])
|
||||
AC_CONFIG_SRCDIR([src/util/json.c])
|
||||
AC_CONFIG_HEADERS([taler_config.h])
|
||||
# support for non-recursive builds
|
||||
AM_INIT_AUTOMAKE([subdir-objects])
|
||||
|
||||
# pretty build rules
|
||||
AM_SILENT_RULES([yes])
|
||||
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
|
||||
LT_INIT
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
|
||||
CFLAGS="-Wall $CFLAGS"
|
||||
|
||||
# Checks for header files.
|
||||
AC_CHECK_HEADERS([stdint.h stdlib.h string.h unistd.h])
|
||||
|
||||
# Check for GNUnet's libgnunetutil.
|
||||
libgnunetutil=0
|
||||
AC_MSG_CHECKING([for libgnunetutil])
|
||||
AC_ARG_WITH(gnunet,
|
||||
[AS_HELP_STRING([--with-gnunet=PFX], [base of GNUnet installation])],
|
||||
[AC_MSG_RESULT([given as $with_gnunet])],
|
||||
[AC_MSG_RESULT(not given)
|
||||
with_gnunet=yes])
|
||||
AS_CASE([$with_gnunet],
|
||||
[yes], [],
|
||||
[no], [AC_MSG_ERROR([--with-gnunet is required])],
|
||||
[LDFLAGS="-L$with_gnunet/lib $LDFLAGS"
|
||||
CPPFLAGS="-I$with_gnunet/include $CPPFLAGS"])
|
||||
AC_CHECK_HEADERS([gnunet/platform.h gnunet/gnunet_util_lib.h],
|
||||
[AC_CHECK_LIB([gnunetutil], [GNUNET_SCHEDULER_run], libgnunetutil=1)],
|
||||
[], [#ifdef HAVE_GNUNET_PLATFORM_H
|
||||
#include <gnunet/platform.h>
|
||||
#endif])
|
||||
AS_IF([test $libgnunetutil != 1],
|
||||
[AC_MSG_ERROR([[
|
||||
***
|
||||
*** You need libgnunetutil to build this program.
|
||||
*** This library is part of GNUnet, available at
|
||||
*** https://gnunet.org
|
||||
*** ]])])
|
||||
|
||||
|
||||
# check for libmicrohttpd
|
||||
microhttpd=0
|
||||
AC_MSG_CHECKING([for microhttpd])
|
||||
AC_ARG_WITH([microhttpd],
|
||||
[AS_HELP_STRING([--with-microhttpd=PFX], [base of microhttpd installation])],
|
||||
[AC_MSG_RESULT([given as $with_microhttpd])],
|
||||
[AC_MSG_RESULT([not given])
|
||||
with_microhttpd=yes])
|
||||
AS_CASE([$with_microhttpd],
|
||||
[yes], [],
|
||||
[no], [AC_MSG_ERROR([--with-microhttpd is required])],
|
||||
[LDFLAGS="-L$with_microhttpd/lib $LDFLAGS"
|
||||
CPPFLAGS="-I$with_microhttpd/include $CPPFLAGS"])
|
||||
AC_CHECK_LIB(microhttpd,MHD_start_daemon,
|
||||
[AC_CHECK_HEADER([microhttpd.h],[microhttpd=1])])
|
||||
AS_IF([test $microhttpd = 0],
|
||||
[AC_MSG_ERROR([[
|
||||
***
|
||||
*** You need libmicrohttpd to build this program.
|
||||
*** ]])])
|
||||
|
||||
|
||||
# check for libpq (postgresql)
|
||||
AX_LIB_POSTGRESQL([9.3])
|
||||
AS_IF([test ! "$found_postgresql" = "yes"],
|
||||
[AC_MSG_ERROR([[
|
||||
***
|
||||
*** You need postgresql / libpq to build this program.
|
||||
*** ]])])
|
||||
|
||||
|
||||
# check for libjansson (Jansson JSON library)
|
||||
jansson=0
|
||||
AC_MSG_CHECKING([for jansson])
|
||||
AC_ARG_WITH([jansson],
|
||||
[AS_HELP_STRING([--with-jansson=PFX], [base of jansson installation])],
|
||||
[AC_MSG_RESULT([given as $with_jansson])],
|
||||
[AC_MSG_RESULT([not given])
|
||||
with_jansson=yes])
|
||||
AS_CASE([$with_jansson],
|
||||
[yes], [],
|
||||
[no], [AC_MSG_ERROR([--with-jansson is required])],
|
||||
[LDFLAGS="-L$with_jansson/lib $LDFLAGS"
|
||||
CPPFLAGS="-I$with_jansson/include $CPPFLAGS"])
|
||||
AC_CHECK_LIB(jansson,json_pack,
|
||||
[AC_CHECK_HEADER([jansson.h],[jansson=1])])
|
||||
AS_IF([test $jansson = 0],
|
||||
[AC_MSG_ERROR([[
|
||||
***
|
||||
*** You need libjansson to build this program.
|
||||
*** ]])])
|
||||
|
||||
# check for libgnurl
|
||||
LIBGNURL_CHECK_CONFIG([], [7.34.0], [gnurl=1], [gnurl=0])
|
||||
if test "$gnurl" = 1
|
||||
then
|
||||
AM_CONDITIONAL(HAVE_LIBGNURL, true)
|
||||
AC_DEFINE([HAVE_LIBGNURL],[1],[Have libgnurl])
|
||||
else
|
||||
AM_CONDITIONAL(HAVE_LIBGNURL, false)
|
||||
fi
|
||||
AS_IF([test $gnurl = 0],
|
||||
[AC_MSG_ERROR([[
|
||||
***
|
||||
*** You need libgnurl to build this program.
|
||||
*** ]])])
|
||||
|
||||
# Require minimum libgcrypt version
|
||||
need_libgcrypt_version=1.6.1
|
||||
AC_DEFINE_UNQUOTED([NEED_LIBGCRYPT_VERSION], ["$need_libgcrypt_version"],
|
||||
[minimum version of libgcrypt required])
|
||||
AM_PATH_LIBGCRYPT([$need_libgcrypt_version])
|
||||
|
||||
# logging
|
||||
extra_logging=0
|
||||
AC_ARG_ENABLE([logging],
|
||||
AS_HELP_STRING([--enable-logging@<:@=value@:>@],[Enable logging calls. Possible values: yes,no,verbose ('yes' is the default)]),
|
||||
[AS_IF([test "x$enableval" = "xyes"], [],
|
||||
[test "x$enableval" = "xno"], [AC_DEFINE([GNUNET_CULL_LOGGING],[],[Define to cull all logging calls])],
|
||||
[test "x$enableval" = "xverbose"], [extra_logging=1]
|
||||
[test "x$enableval" = "xveryverbose"], [extra_logging=2])
|
||||
], [])
|
||||
AC_DEFINE_UNQUOTED([GNUNET_EXTRA_LOGGING],[$extra_logging],[1 if extra logging is enabled, 2 for very verbose extra logging, 0 otherwise])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_TYPE_PID_T
|
||||
AC_TYPE_SIZE_T
|
||||
AC_TYPE_UINT16_T
|
||||
AC_TYPE_UINT32_T
|
||||
AC_TYPE_UINT64_T
|
||||
AC_TYPE_INTMAX_T
|
||||
AC_TYPE_UINTMAX_T
|
||||
|
||||
# Checks for library functions.
|
||||
AC_CHECK_FUNCS([strdup])
|
||||
|
||||
AC_CONFIG_FILES([Makefile
|
||||
doc/Makefile
|
||||
src/Makefile
|
||||
src/include/Makefile
|
||||
src/util/Makefile
|
||||
src/mint/Makefile
|
||||
])
|
||||
AC_OUTPUT
|
1
contrib/mint-template/README
Normal file
1
contrib/mint-template/README
Normal file
@ -0,0 +1 @@
|
||||
This directory is a template for the mint directory.
|
6
contrib/mint-template/config/mint-common.conf
Normal file
6
contrib/mint-template/config/mint-common.conf
Normal file
@ -0,0 +1,6 @@
|
||||
[mint]
|
||||
db = postgres:///taler
|
||||
port = 4241
|
||||
master_pub = ...
|
||||
refresh_security_parameter = 3
|
||||
|
79
contrib/mint-template/config/mint-keyup.conf
Normal file
79
contrib/mint-template/config/mint-keyup.conf
Normal file
@ -0,0 +1,79 @@
|
||||
[mint_keys]
|
||||
|
||||
# how long is one signkey valid?
|
||||
signkey_duration = 4 weeks
|
||||
|
||||
# how long do we generate denomination and signing keys
|
||||
# ahead of time?
|
||||
lookahead_sign = 32 weeks 1 day
|
||||
|
||||
# how long do we provide to clients denomination and signing keys
|
||||
# ahead of time?
|
||||
lookahead_provide = 4 weeks 1 day
|
||||
|
||||
# what coin types do we have available?
|
||||
coin_types = default_eur_ct_10 default_eur_5 default_eur_10 default_eur_1000
|
||||
|
||||
|
||||
|
||||
[mint_denom_duration_overlap]
|
||||
default_eur_ct_10 = 5 minutes
|
||||
default_eur_5 = 5 minutes
|
||||
default_eur_10 = 5 minutes
|
||||
default_eur_1000 = 5 minutes
|
||||
|
||||
|
||||
|
||||
[mint_denom_value]
|
||||
default_eur_ct_10 = EUR:0.10
|
||||
default_eur_5 = EUR:5
|
||||
default_eur_10 = EUR:10
|
||||
default_eur_1000 = EUR:1000
|
||||
|
||||
|
||||
|
||||
[mint_denom_duration_withdraw]
|
||||
default_eur_ct_10 = 7 days
|
||||
default_eur_5 = 7 days
|
||||
default_eur_10 = 7 days
|
||||
default_eur_1000 = 1 day
|
||||
|
||||
|
||||
|
||||
[mint_denom_duration_spend]
|
||||
default_eur_ct_10 = 30 days
|
||||
default_eur_5 = 30 days
|
||||
default_eur_10 = 30 days
|
||||
default_eur_1000 = 30 day
|
||||
|
||||
|
||||
|
||||
[mint_denom_fee_withdraw]
|
||||
default_eur_ct_10 = EUR:0.01
|
||||
default_eur_5 = EUR:0.01
|
||||
default_eur_10 = EUR:0.01
|
||||
default_eur_1000 = EUR:0.01
|
||||
|
||||
|
||||
[mint_denom_fee_deposit]
|
||||
default_eur_ct_10 = EUR:0.01
|
||||
default_eur_5 = EUR:0.01
|
||||
default_eur_10 = EUR:0.01
|
||||
default_eur_1000 = EUR:0.01
|
||||
|
||||
|
||||
|
||||
[mint_denom_fee_refresh]
|
||||
default_eur_ct_10 = EUR:0.01
|
||||
default_eur_5 = EUR:0.01
|
||||
default_eur_10 = EUR:0.01
|
||||
default_eur_1000 = EUR:0.01
|
||||
|
||||
|
||||
|
||||
[mint_denom_kappa]
|
||||
default_eur_ct_10 = 3
|
||||
default_eur_5 = 3
|
||||
default_eur_10 = 3
|
||||
default_eur_1000 = 5
|
||||
|
12
doc/.gitignore
vendored
Normal file
12
doc/.gitignore
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
*.aux
|
||||
*.dvi
|
||||
*.log
|
||||
*.pdf
|
||||
*.out
|
||||
*.snm
|
||||
*.toc
|
||||
*.vrb
|
||||
*.nav
|
||||
*/auto
|
||||
api-sphinx/_build
|
||||
api-sphinx/*.html
|
5
doc/Makefile.am
Normal file
5
doc/Makefile.am
Normal file
@ -0,0 +1,5 @@
|
||||
EXTRA_DIST = \
|
||||
paper/taler.tex
|
||||
paper/ref.bib \
|
||||
paper/Makefile
|
||||
|
3474
doc/logos/ai/logotalerv2.ai
Normal file
3474
doc/logos/ai/logotalerv2.ai
Normal file
File diff suppressed because one or more lines are too long
BIN
doc/logos/eps/icon_taler.eps
Normal file
BIN
doc/logos/eps/icon_taler.eps
Normal file
Binary file not shown.
BIN
doc/logos/eps/logo_taler.eps
Normal file
BIN
doc/logos/eps/logo_taler.eps
Normal file
Binary file not shown.
BIN
doc/logos/fonts/OldNewspaperTypes.ttf
Executable file
BIN
doc/logos/fonts/OldNewspaperTypes.ttf
Executable file
Binary file not shown.
BIN
doc/logos/fonts/perpetue/Perpetua Bold Italic.ttf
Normal file
BIN
doc/logos/fonts/perpetue/Perpetua Bold Italic.ttf
Normal file
Binary file not shown.
BIN
doc/logos/fonts/perpetue/Perpetua Bold.ttf
Normal file
BIN
doc/logos/fonts/perpetue/Perpetua Bold.ttf
Normal file
Binary file not shown.
BIN
doc/logos/fonts/perpetue/Perpetua Italic.ttf
Normal file
BIN
doc/logos/fonts/perpetue/Perpetua Italic.ttf
Normal file
Binary file not shown.
BIN
doc/logos/fonts/perpetue/Perpetua.ttf
Normal file
BIN
doc/logos/fonts/perpetue/Perpetua.ttf
Normal file
Binary file not shown.
133
doc/logos/fonts/smoth_bight/End User Licence Agreement.txt
Executable file
133
doc/logos/fonts/smoth_bight/End User Licence Agreement.txt
Executable file
@ -0,0 +1,133 @@
|
||||
End User License Agreement and Software Inclusion Agreement
|
||||
|
||||
|
||||
"Purchaser" and "User" may be used interchangeably in this agreement.
|
||||
|
||||
|
||||
The official release page is at kustren.deviantart.com/
|
||||
|
||||
or
|
||||
|
||||
|
||||
|
||||
Copyright 2013 Kustren
|
||||
Trademark 2013 Kustren licence
|
||||
Commercial distribution, rendering and printing of the font and derived work is prohibited.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Usage
|
||||
|
||||
Smoth-Bight is freeware Font is free to use for personal and commercial purposes. No payment is necessary, and there is no limit to the amount of prints, pages, or other medium to be produced using them. However, you cannot offer the font for commercial sale, or offer for direct download. The inclusion othe font name and/or site URL in the credits or documentation when it is used is appreciated, but this is not mandatory.
|
||||
My font is for personal and commercial use, can be used for any type of work, while nature, neither will be able to be modified in any kind of way.
|
||||
This license is multipurpose, my font can be used on multiple computers at once.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Payment
|
||||
|
||||
Payment is not required for the use of kustren's freeware Font.
|
||||
|
||||
|
||||
|
||||
Support
|
||||
|
||||
If you experience problems with any Kustren's Freeware font (such as spacing issues or missing characters), please verify that you have the correct and current version of the fonts. In the case of Freeware font, downloading the font directly from the http://kustren.deviantart.com/ site will ensure that the font files have not been altered.
|
||||
|
||||
|
||||
|
||||
|
||||
Copyright (c) 2014 by Kustren. All rights reserved.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
77
doc/logos/fonts/smoth_bight/Licencia de la fuente - Version en Espa§ol.txt
Executable file
77
doc/logos/fonts/smoth_bight/Licencia de la fuente - Version en Espa§ol.txt
Executable file
@ -0,0 +1,77 @@
|
||||
Contrato de licencia de usuario final e Inclusión del acuerdo de Software
|
||||
|
||||
"Comprador " y "Usuario " se pueden utilizar indistintamente en el presente acuerdo .
|
||||
|
||||
|
||||
La página oficial de lanzamiento de la fuente es:
|
||||
http://kustren.deviantart.com/
|
||||
|
||||
|
||||
|
||||
Derechos de autor 2013 Kustren
|
||||
Marcas 2013 licencia Kustren
|
||||
Se prohíbe la distribución comercial, la representación y la impresión de la fuente y el trabajo derivado .
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Uso
|
||||
|
||||
La fuente de Kustren llamada Smoth-Bight es freware en su mayoria, de uso libre, pero solo para fines personales y/o comerciales, no hay limite en la cantidad de copias realizadas de la mis ma fuente en los pcs que usted utilice.
|
||||
Sin embargo no pueden ofrecer esta tipografia ni como suyas y/o comercializarla, tampoco estara permitida la descarga directa en otras paginas web, a menos que sea con consentimiento de su creador Kustren.
|
||||
Si usted usa mi fuente deme creditos por ello y/o coloque la pagina web mia, esto es de agradecer.
|
||||
|
||||
licencia del derecho de uso
|
||||
|
||||
Esta fuente es para uso personal y/o comercial, puede ser usadas para cualquier tipo de trabajo, pero no podra ser modificadas de ningun tipo de manera.
|
||||
Recuerden que si ustedes compran alguna tipografia no se convierten en propietariuo de la fuente, solo obtienen la licencia de uso, es decir la misma que estan leyendo.
|
||||
Esta licencia es de multiuso, mi fuente pueden ser usadas en multiples computadores a la vez.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
pago
|
||||
|
||||
El pago no es necesaria para el uso de esta fuente de software gratuito creada por kustren.
|
||||
|
||||
|
||||
|
||||
apoyo
|
||||
|
||||
Si tienen problema con la fuente (como problemas de espaciado o caracteres que faltan ) , por favor, compruebe que tiene la versión correcta y actualizada de la fuente. En el caso de fuentes de dominio público , la descarga de la fuente directamente desde el sitio http://kustren.deviantart.com/ se asegurará de que los archivos de fuentes no han sido alterados.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
BIN
doc/logos/fonts/smoth_bight/Smoth-Bight - Por Kustren.otf
Executable file
BIN
doc/logos/fonts/smoth_bight/Smoth-Bight - Por Kustren.otf
Executable file
Binary file not shown.
BIN
doc/logos/fonts/smoth_bight/Smoth-Bight Italic - Por Kustren.otf
Executable file
BIN
doc/logos/fonts/smoth_bight/Smoth-Bight Italic - Por Kustren.otf
Executable file
Binary file not shown.
BIN
doc/logos/ico/favicon1616.ico
Normal file
BIN
doc/logos/ico/favicon1616.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
BIN
doc/logos/ico/favicon4848.ico
Normal file
BIN
doc/logos/ico/favicon4848.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
doc/logos/png/icon_taler.png
Normal file
BIN
doc/logos/png/icon_taler.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 MiB |
BIN
doc/logos/png/logo_taler.png
Normal file
BIN
doc/logos/png/logo_taler.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 368 KiB |
15
doc/paper/.latexmkrc
Normal file
15
doc/paper/.latexmkrc
Normal file
@ -0,0 +1,15 @@
|
||||
add_cus_dep('glo', 'gls', 0, 'run_makeglossaries');
|
||||
add_cus_dep('acn', 'acr', 0, 'run_makeglossaries');
|
||||
|
||||
sub run_makeglossaries {
|
||||
if ( $silent ) {
|
||||
system "makeglossaries -q '$_[0]'";
|
||||
}
|
||||
else {
|
||||
system "makeglossaries '$_[0]'";
|
||||
};
|
||||
}
|
||||
|
||||
push @generated_exts, 'glo', 'gls', 'glg';
|
||||
push @generated_exts, 'acn', 'acr', 'alg';
|
||||
$clean_ext .= ' %R.ist %R.xdy';
|
94
doc/paper/taler.bib
Normal file
94
doc/paper/taler.bib
Normal file
@ -0,0 +1,94 @@
|
||||
@article{nakamoto2008bitcoin,
|
||||
title={Bitcoin: A peer-to-peer electronic cash system},
|
||||
author={Nakamoto, Satoshi},
|
||||
year={2008}
|
||||
}
|
||||
|
||||
@Article{blum1981,
|
||||
author = {Manuel Blum},
|
||||
title = {Coin Flipping by Telephone},
|
||||
journal = {CRYPTO},
|
||||
year = {1981},
|
||||
pages = {11-15},
|
||||
}
|
||||
|
||||
@inproceedings{chaum1990untraceable,
|
||||
title={Untraceable electronic cash},
|
||||
author={Chaum, David and Fiat, Amos and Naor, Moni},
|
||||
booktitle={Proceedings on Advances in cryptology},
|
||||
pages={319--327},
|
||||
year={1990},
|
||||
organization={Springer-Verlag New York, Inc.}
|
||||
}
|
||||
|
||||
@inproceedings{chaum1983blind,
|
||||
title={Blind signatures for untraceable payments},
|
||||
author={Chaum, David},
|
||||
booktitle={Advances in cryptology},
|
||||
pages={199--203},
|
||||
year={1983},
|
||||
organization={Springer}
|
||||
}
|
||||
|
||||
@inproceedings{rivest2004peppercoin,
|
||||
title={Peppercoin micropayments},
|
||||
author={Rivest, Ronald L},
|
||||
booktitle={Financial Cryptography},
|
||||
pages={2--8},
|
||||
year={2004},
|
||||
organization={Springer}
|
||||
}
|
||||
|
||||
@inproceedings{miers2013zerocoin,
|
||||
title={Zerocoin: Anonymous distributed e-cash from bitcoin},
|
||||
author={Miers, Ian and Garman, Christina and Green, Matthew and Rubin, Aviel D},
|
||||
booktitle={Security and Privacy (SP), 2013 IEEE Symposium on},
|
||||
pages={397--411},
|
||||
year={2013},
|
||||
organization={IEEE}
|
||||
}
|
||||
|
||||
@inproceedings{selby2004analyzing,
|
||||
title={Analyzing the Success and Failure of Recent e-Payment Schemes},
|
||||
author={Selby, Jack R},
|
||||
booktitle={Financial Cryptography},
|
||||
pages={1--1},
|
||||
year={2004},
|
||||
organization={Springer}
|
||||
}
|
||||
|
||||
@misc{brands1993efficient,
|
||||
title={An efficient off-line electronic cash system based on the representation problem},
|
||||
author={Brands, Stefan A},
|
||||
year={1993},
|
||||
publisher={Centrum voor Wiskunde en Informatica}
|
||||
}
|
||||
|
||||
@article{dent2008extensions,
|
||||
title={Extensions to Chaum's Blind Signature Scheme and OpenCoin Requirements},
|
||||
author={Dent, AW and Paterson, KG and Wild, PR},
|
||||
year={2008}
|
||||
}
|
||||
|
||||
@article{dent2008preliminary,
|
||||
title={Preliminary Report on Chaum's Online E-Cash Architecture},
|
||||
author={Dent, AW and Paterson, KG and Wild, PR},
|
||||
journal={Royal Holloway, University of London},
|
||||
year={2008}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@inproceedings{tor-design,
|
||||
title = {Tor: The Second-Generation Onion Router},
|
||||
author = {Roger Dingledine and Nick Mathewson and Paul Syverson},
|
||||
booktitle = {Proceedings of the 13th USENIX Security Symposium},
|
||||
year = {2004},
|
||||
month = {August},
|
||||
www_important = {1},
|
||||
www_tags = {selected},
|
||||
www_html_url = {https://www.torproject.org/svn/trunk/doc/design-paper/tor-design.html},
|
||||
www_pdf_url = {https://www.torproject.org/svn/trunk/doc/design-paper/tor-design.pdf},
|
||||
www_section = {Anonymous communication},
|
||||
}
|
||||
|
995
doc/paper/taler.tex
Normal file
995
doc/paper/taler.tex
Normal file
@ -0,0 +1,995 @@
|
||||
\documentclass{llncs}
|
||||
%\usepackage[margin=1in,a4paper]{geometry}
|
||||
\usepackage[T1]{fontenc}
|
||||
\usepackage{palatino}
|
||||
\usepackage{xspace}
|
||||
\usepackage{microtype}
|
||||
\usepackage{tikz}
|
||||
\usepackage{amsmath,amssymb}
|
||||
\usepackage{enumitem}
|
||||
\usetikzlibrary{shapes,arrows}
|
||||
\usetikzlibrary{positioning}
|
||||
\usetikzlibrary{calc}
|
||||
|
||||
|
||||
|
||||
% Terminology:
|
||||
% - SEPA-transfer -- avoid 'SEPA transaction' as we use
|
||||
% 'transaction' already when we talk about taxable
|
||||
% transfers of Taler coins and database 'transactions'.
|
||||
% - wallet = coins at customer
|
||||
% - reserve = currency entrusted to mint waiting for withdrawl
|
||||
% - deposit = SEPA to mint
|
||||
% - withdrawl = mint to customer
|
||||
% - spending = customer to merchant
|
||||
% - redeeming = merchant to mint (and then mint SEPA to merchant)
|
||||
% - refreshing = customer-mint-customer
|
||||
% - dirty coin = coin with exposed public key
|
||||
% - fresh coin = coin that was refreshed or is new
|
||||
% - coin signing key = mint's online key used to (blindly) sign coin
|
||||
% - message signing key = mint's online key to sign mint messages
|
||||
% - mint master key = mint's key used to sign other mint keys
|
||||
% - owner = entity that knows coin private key
|
||||
% - transaction = coin ownership transfer that should be taxed
|
||||
% - sharing = coin copying that should not be taxed
|
||||
|
||||
|
||||
\title{Taler: Taxable Anonymous Libre Electronic Reserves}
|
||||
|
||||
\begin{document}
|
||||
\mainmatter
|
||||
|
||||
%\author{Florian Dold \and Sree Harsha Totakura \and Benedikt M\"uller \and Christian Grothoff}
|
||||
%\institute{The GNUnet Project}
|
||||
|
||||
|
||||
\maketitle
|
||||
|
||||
\begin{abstract}
|
||||
This paper introduces Taler, a Chaum-style digital currency using
|
||||
blind signatures that enables anonymous payments while ensuring that
|
||||
entities that receive payments are auditable and thus taxable. Taler
|
||||
differs from Chaum's original proposal in that customers can never defraud anyone,
|
||||
merchants can only fail to deliver the merchandise to the customer,
|
||||
and mints can be fully audited. Consequently, enforcement of honest
|
||||
behavior is better and more timely than with Chaum, and is at least as
|
||||
strict as with legacy credit card payment systems that do not provide
|
||||
for privacy. Furthermore, Taler allows fractional and incremental
|
||||
payments, and even in this case is still able to guarantee
|
||||
unlinkability of transactions via a new coin refreshing protocol.
|
||||
Finally, Taler also supports microdonations using probabilistic
|
||||
transactions. We argue that Taler provides a secure digital currency
|
||||
for modern liberal societies as it is a flexible, libre and efficient
|
||||
protocol and adequately balances the state's need for monetary control
|
||||
with the citizen's needs for private economic activity.
|
||||
\end{abstract}
|
||||
|
||||
\section{Introduction}
|
||||
|
||||
The design of payment systems shapes economies and societies. Strong,
|
||||
developed nation states are evolving towards fully transparent payment
|
||||
systems, such as the MasterCard and VisaCard credit card schemes and
|
||||
computerized bank transactions such as SWIFT. Such systems enable
|
||||
mass surveillance and thus extensive government control over the
|
||||
economy, from taxation to intrusion into private lives. Bribery and
|
||||
corruption are limited to elites that can afford to escape the
|
||||
dragnet. The other extreme are economies of developing, weak nation
|
||||
states where economic activity is based largely on coins, paper money
|
||||
or even barter. Here, the state is often unable to effectively
|
||||
monitor or tax economic activity, and this limits the ability of the
|
||||
state to shape the society. As bribery is virtually impossible to
|
||||
detect, it is widespread and not limited to social elites.
|
||||
ZeroCoin~\cite{miers2013zerocoin} is an example for translating such
|
||||
an economy into the digital realm.
|
||||
|
||||
Taler is supposed to offer a middleground between an authoritarian
|
||||
state in total control of the population and weak states with almost
|
||||
anarchistic economies. Specifically, we believe that a liberal
|
||||
democracy needs a payment system with the following properties:
|
||||
|
||||
\begin{description}
|
||||
\item[Customer Anonymity] It must be impossible for mints, merchants
|
||||
and even a global active adversary, to trace the spending behavior
|
||||
of a customer.
|
||||
\item[Unlinkability] Merchants must not be able to tell if two
|
||||
transactions were performed by the same customer. It must be
|
||||
infeasible to link a set of transactions to the same (anonymous)
|
||||
customer. %, even when taking aborted transactions into account.
|
||||
\item[Taxability] In many current legal systems, it is the
|
||||
responsibility of the merchant to deduct (sales) taxes from
|
||||
purchases made by customers, or to pay (income) taxes for payments
|
||||
received for work.
|
||||
%Taxation is neccessary for the state to
|
||||
%provide legitimate social functions, such as education. Thus, a payment
|
||||
%system must facilitate sales, income and transaction taxes.
|
||||
This specifically means that it must be able to audit merchants (or
|
||||
generally anybody receiving money), and thus the receiver of
|
||||
electronic cash must be easily identifiable.
|
||||
%non-anonymous, as this would enable tax fraud.
|
||||
\item[Verifiability] The payment system should try to minimize the
|
||||
trust necessary between the participants. In particular, digital
|
||||
signatures should be used extensively in order to be able to
|
||||
resolve disputes between the involved parties. Nevertheless,
|
||||
customers must never be able to defraud anyone, and merchants must
|
||||
at best be able to defraud their customers by not delivering the
|
||||
on the agreed contract. Neither merchants nor customers must ever
|
||||
be able to commit fraud against the mint. Both customers and
|
||||
merchants must receive cryptographic proofs of bad behavior in
|
||||
case of protocol violations by the mint. Thus, only the mint will
|
||||
have to be tightly audited and regulated. The design must make it
|
||||
easy to audit the finances of the mint.
|
||||
\item[Ease of Deployment] %The system should be easy to deploy for
|
||||
% real-world applications. In order to lower the entry barrier and
|
||||
% acceptance of the system, a gateway to the existing financial
|
||||
% system should be provided, i.e. by integrating internet-banking
|
||||
% protocols such as HBCI/FinTAN.
|
||||
The digital currency should be
|
||||
tied 1:1 to existing currencies (such as EUR or USD) to avoid
|
||||
exposing users to unnecessary risks from currency fluctuations.
|
||||
Moreover, the system must have a free software reference
|
||||
implementation and an open protocol standard.
|
||||
% The protocol should
|
||||
% be able to run easily over HTTP(S).
|
||||
\item[Low resource consumption] In order to minimize the operating
|
||||
costs and environmental impact of the payment system, it must
|
||||
avoid the reliance on expensive and ``wasteful'' computations
|
||||
such as proof-of-work.
|
||||
\item[Large Payments and Microdonations] The payment system needs to
|
||||
handle large payments in a reliable manner. Furthermore, for
|
||||
microdonations the system should allow sacrificing reliability to
|
||||
achieve economic viability.
|
||||
\end{description}
|
||||
|
||||
Taler builds on ideas from Chaum~\cite{chaum1983blind}, who proposed a
|
||||
digital currency system that would provide (some) customer anonymity
|
||||
while disclosing the identity of the merchants. Chaum's digital cash
|
||||
system had some limitations and ultimately failed to be widely
|
||||
adopted. In our assessment, key reasons include:
|
||||
|
||||
\begin{itemize}
|
||||
\item The use of patents to protect the technology; a payment system
|
||||
must be libre --- free software --- to have a chance for widespread
|
||||
adoption.
|
||||
\item The use of off-line payments and thus deferred detection of
|
||||
double-spending, which could require the mint to attempt to recover
|
||||
funds from customers via the legal system. This creates a
|
||||
significant business risk for the mint, as the system is not
|
||||
self-enforcing from the perspective of the mint. In 1983 off-line
|
||||
payments might have been a necessary feature. However, today
|
||||
requiring network connectivity is feasible and avoids the business
|
||||
risks associated with deferred fraud detection.
|
||||
\item % In addition to the risk of legal disputes with fradulent
|
||||
% merchants and customers,
|
||||
Chaum's published design does not clearly
|
||||
limit the financial damage a mint might suffer from the
|
||||
disclosure of its private online signing key.
|
||||
% \item Chaum did not support fractional payments, and Brand's
|
||||
% extensions for fractional payments broke unlinkability and thus
|
||||
% limited anonymity. Chaum also did not support microdonations,
|
||||
% leaving an opportunity for expanding payments into additional areas
|
||||
% unexplored.
|
||||
% \item Chaum's system was implemented at a time where the US market
|
||||
% was still dominated by paper checks and the European market was
|
||||
% fragmented into dozens of currencies. Today, SEPA provides a
|
||||
% unified currency and currency transfer method for most of Europe,
|
||||
% significantly lowering the barrier to entry into this domain for
|
||||
% a larger market.
|
||||
\end{itemize}
|
||||
|
||||
This paper describes Taler, a simple and practical payment with the
|
||||
above goals in mind. The basic idea is to use Chaum's model of
|
||||
customer, merchant and mint (Figure~\ref{fig:cmm}) where the customer
|
||||
withdraws digital currency from the mint with unlinkability provided
|
||||
via blind signatures. In contrast to Chaum, Taler uses online
|
||||
detection of double-spending, thus ensuring the merchant instantly
|
||||
that a transaction is valid. Instead of using cryptographic methods
|
||||
to enable fractional payments, the customer can simply include
|
||||
the fraction of a coin's value that is to be paid to the merchant in
|
||||
his message to the merchant.
|
||||
|
||||
|
||||
\begin{figure}[h]
|
||||
\centering
|
||||
\begin{tikzpicture}
|
||||
|
||||
|
||||
\tikzstyle{def} = [node distance= 7em and 10em, inner sep=1em, outer sep=.3em];
|
||||
\node (origin) at (0,0) {};
|
||||
\node (mint) [def,above=of origin,draw]{Mint};
|
||||
\node (customer) [def, draw, below left=of origin] {Customer};
|
||||
\node (merchant) [def, draw, below right=of origin] {Merchant};
|
||||
|
||||
\tikzstyle{C} = [color=black, line width=1pt]
|
||||
\draw [<-, C] (customer) -- (mint) node [midway, above, sloped] (TextNode) {withdraw coins};
|
||||
\draw [<-, C] (mint) -- (merchant) node [midway, above, sloped] (TextNode) {deposit coins};
|
||||
\draw [<-, C] (merchant) -- (customer) node [midway, above, sloped] (TextNode) {spend coins};
|
||||
\end{tikzpicture}
|
||||
\caption{Taler's system model for the payment system is based on Chaum~\cite{chaum1983blind}.}
|
||||
\label{fig:cmm}
|
||||
\end{figure}
|
||||
|
||||
Online fraud detection can create problems if the network fails during
|
||||
the initial steps of a transaction. For example, a law enforcement
|
||||
agency might try to entrap a customer by offering illicit goods and
|
||||
then aborting the transaction after learning the public key of the
|
||||
coin. If the customer were to then later spend that coin on a
|
||||
purchase with shipping, the law enforcement agency could link the two
|
||||
transactions and might be able to use the shipping to deanonymize the
|
||||
customer. Similarly, fractional payments also lead to the
|
||||
possibility of customers wanting to legitimately use the same coin
|
||||
twice. Taler addresses this problem by allowing customers to {\em
|
||||
refresh} coins. Refreshing means that a customer is able to
|
||||
exchange one coin for a fresh coin, with the old and the new coin
|
||||
being unlinkable (except for the customer himself). Taler ensures
|
||||
that the {\em entity} of the user owning the new coin is the same as the
|
||||
entity of the user owning the old coin, thus making sure that the
|
||||
refreshing protocol cannot be abused for money laundering or other
|
||||
illicit transactions.
|
||||
|
||||
|
||||
\section{Related Work}
|
||||
|
||||
\subsection{Blockchain-based currencies}
|
||||
|
||||
In recent years, a class of decentralized electronic payment systems,
|
||||
based on collectively recorded and verified append-only public
|
||||
ledgers, have gained immense popularity. The most well-known protocol
|
||||
in this class is Bitcoin~\cite{nakamoto2008bitcoin}. An initial
|
||||
concern with Bitcoin was the lack of anonymity, as all Bitcoin
|
||||
transactions are recorded for eternity, which can enable
|
||||
identification of users. In theory, this concern has been addressed
|
||||
with the Zerocoin extension to the protocol~\cite{miers2013zerocoin}.
|
||||
|
||||
While these protocols dispense with the need for a central, trusted
|
||||
authority and provide anonymity, we argue there are some major,
|
||||
irredeemable problems inherent in these systems:
|
||||
|
||||
\begin{itemize}
|
||||
\item Bitcoins are not (easily) taxable. The legality and legitimacy of
|
||||
this aspect is questionable. The Zerocoin extension would only make
|
||||
this worse.
|
||||
\item Bitcoins can not be bound to any fiat currency, and are subject to
|
||||
significant value fluctuations. While such fluctuations may be
|
||||
acceptable for high-risk investments, they make Bitcoin unsuitable as
|
||||
a medium of exchange.
|
||||
\item The computational puzzles solved by Bitcoin nodes with the purpose
|
||||
of securing the block chain
|
||||
consume a considerable amount of computational resources and thus
|
||||
energy. Thus, Bitcoin does not represent an environmentally responsible
|
||||
design.
|
||||
\item Anyone can easily start an alternative Bitcoin transaction chain
|
||||
(a so-called AltCoin) and, if successful, reap the benefits of the low
|
||||
cost to initially create coins via computation. As a result, dozens of
|
||||
AltCoins have been created, often without any significant changes to the
|
||||
technology. A large number of AltCoins creates additional overheads for
|
||||
currency exchange and exascerbates the problems with currency fluctuations.
|
||||
\end{itemize}
|
||||
|
||||
\subsection{Chaum-style electronic cash}
|
||||
|
||||
Chaum's original digital cash system~\cite{chaum1983blind} was
|
||||
extended by Brands~\cite{brands1993efficient} with the ability to
|
||||
perform fractional payments; however, the transactions performed with
|
||||
the same coin then become linkable.
|
||||
%
|
||||
%Some argue that the focus on technically perfect but overwhelmingly
|
||||
%complex protocols, as well as the the lack of usable, practical
|
||||
%solutions lead to an abandonment of these ideas by
|
||||
%practitioners~\cite{selby2004analyzing}.
|
||||
%
|
||||
To our knowledge, the only publicly available effort to implement
|
||||
Chaum's idea is
|
||||
Opencoin~\cite{dent2008extensions}. However,
|
||||
Opencoin seems to be neither actively developed nor used, and it is
|
||||
not clear to what degree the implementation is even complete. Only a
|
||||
partial description of the Opencoin protocol is available to date.
|
||||
|
||||
\subsection{Peppercoin}
|
||||
|
||||
Peppercoin~\cite{rivest2004peppercoin} is a microdonation protocol.
|
||||
The main idea of the protocol is to reduce transaction costs by
|
||||
minimizing the number of transactions that are processed directly by
|
||||
the mint. Instead of always paying, the customer ``gambles'' with the
|
||||
merchant for each microdonation. Only if the merchant wins, the
|
||||
microdonation is upgraded to a macropayment to be deposited at the
|
||||
mint. Peppercoin does not provide customer-anonymity. The proposed
|
||||
statistical method for mints detecting fraudulent cooperation between
|
||||
customers and merchants at the expense of the mint not only creates
|
||||
legal risks for the mint (who has to make a statistical argument), but
|
||||
also would require the mint to learn about microdonations where the
|
||||
merchant did not get upgraded to a macropayment. Thus, it is unclear
|
||||
how much Peppercoin would actually do to reduce the computational
|
||||
burden on the mint.
|
||||
|
||||
|
||||
\section{Design}
|
||||
|
||||
The payment system we propose is built on the blind signature
|
||||
primitive proposed by Chaum, but extended with additional
|
||||
constructions to provide unlinkability, online fraud detection and
|
||||
taxability.
|
||||
|
||||
As with Chaum, the Taler system comprises three principal types of
|
||||
actors: The \emph{customer} is interested in receiving goods or
|
||||
services from the \emph{merchant} in exchange for payment. When
|
||||
making a transaction, both the customer and the merchant must agree on
|
||||
the same \emph{mint}, which serves as an intermediary for the
|
||||
financial transaction between the two. The mint is responsible for
|
||||
allowing the customer to obtain the anonymous digital currency and for
|
||||
enabling the merchant to convert the anonymous digital currency back
|
||||
to some traditional currency.
|
||||
|
||||
\subsection{Security model}
|
||||
|
||||
Taler's security model assumes that cryptographic primitives are
|
||||
secure and that each participant is under full control of his system.
|
||||
The contact information of the mint is known to both customer and
|
||||
merchant from the start. Furthermore, the merchant is known to the
|
||||
customer and we assume that an anonymous, reliable bi-directional
|
||||
communication channel can be established by the customer to both the
|
||||
mint and the merchant.
|
||||
|
||||
The mint is trusted to hold funds of its customers and to forward them
|
||||
when receiving the respective deposit instructions from the merchants.
|
||||
Customer and merchant can have some assurances about the mint's
|
||||
liquidity and operation, as the mint has proven reserves, is subject
|
||||
to the law, and can have its business is regularly audited (for
|
||||
example, by the government or a trusted third party auditor).
|
||||
Audits of the mint's accounts must reveal any possible fraud.
|
||||
%
|
||||
The merchant is trusted to deliver the service or goods to the
|
||||
customer upon receiving payment. The customer can seek legal relief
|
||||
to achieve this, as he must get cryptographic proofs of the contract
|
||||
and that he paid his obligations.
|
||||
%
|
||||
Neither the merchant nor the customer may have any ability to {\em
|
||||
effectively} defraud the mint or the state collecting taxes. Here,
|
||||
``effectively'' means that the expected return for fraud is negative.
|
||||
%
|
||||
Note that customers do not need to be trusted in any way, and that in
|
||||
particular it is never necessary for anyone to try to recover funds
|
||||
from customers using legal means.
|
||||
|
||||
|
||||
\subsection{Taxability and Entities}
|
||||
|
||||
Electronic coins are trivially copied between machines. Thus, we must
|
||||
clarify what kinds of operations can even be expected to be taxed.
|
||||
After all, without instrusive measures to take away control of the
|
||||
computing platform from its users, copying an electronic wallet from
|
||||
one computer to another can hardly be prevented by a payment system.
|
||||
Furthermore, it would also hardly be appropriate to tax the moving of
|
||||
funds between two computers owned by the same individual. We thus
|
||||
need to clarify which kinds of transfers we expect to tax.
|
||||
|
||||
Taler is supposed to ensure that the state can tax {\em transactions}.
|
||||
We define a transaction as the transfer of funds between {\em mutually
|
||||
distrustful} entities. Two entities are assumed to be mutually
|
||||
distrustful if they are unwilling to share control over assets. If a
|
||||
private key is shared between two entities, then both entities have
|
||||
equal access to the credentials represented by the private key. In a
|
||||
payment system this means that either entity could spent the
|
||||
associated funds. Assuming the payment system has effective
|
||||
double-spending detection, this means that either entity has to
|
||||
constantly fear that the funds might no longer be available to it.
|
||||
Thus, ``transfering'' funds by sharing a private key implies that
|
||||
receiving party must trust the sender. In Taler, making funds
|
||||
available by sharing a private key and thus sharing control is {\bf
|
||||
not} considered a {\em transaction} and thus {\bf not} recorded for
|
||||
taxation.
|
||||
|
||||
A {\em transaction} is a transfer where it is assured that one entity
|
||||
gains control over funds while at the same time another entity looses
|
||||
control over those funds. Taler ensures taxability only when some
|
||||
entity acquires exclusive control over digital coins. For
|
||||
transactions, the state can obtain information from the mint (or the
|
||||
bank) that identifies the entity that received the digital coins as
|
||||
well as the exact value of those coins. Taler also allows the mint
|
||||
(and thus the state) to learn the value of digital coins withdrawn by
|
||||
a customer --- but not how, where or when they were spent. Finally,
|
||||
to enable audits, the current balance and profits of the mint are also
|
||||
easily determined.
|
||||
|
||||
\subsection{Anonymity}
|
||||
|
||||
An anonymous communication channel (e.g. via Tor~\cite{tor-design}) is
|
||||
used for all communication between the customer and the merchant.
|
||||
Thus, the customer can remain anonymous; however, the system does reveal
|
||||
that the customer is one of the patrons of the mint. Naturally, the
|
||||
customer-merchant operation might leak other information about the
|
||||
customer, such as a shipping address. Such purchase-specific
|
||||
information leakage is outside of the scope of this work.
|
||||
|
||||
The customer may use an anonymous communication channel for the
|
||||
communication with the mint to avoid leaking IP address information;
|
||||
however, the mint will anyway be able to determine the customer's
|
||||
identity from the (SEPA) transfer that the customer initiates to
|
||||
obtain anonymous digital cash. The scheme is anonymous
|
||||
because the mint will be unable to link the known identity of the
|
||||
customer that withdrew anonymous digital currency to the {\em
|
||||
purchase} performed later at the merchant.
|
||||
% All the mint will be
|
||||
%able to confirm is that the customer is {\em one} of its patrons who
|
||||
%previously obtained the anonymous digital currency --- and of course
|
||||
%that the coin was not spent before.
|
||||
|
||||
While the customer thus has anonymity for his purchase, the mint will
|
||||
always learn the merchant's identity (which is necessary for
|
||||
taxation), and thus the merchant has no reason to anonymize his
|
||||
communication with the mint.
|
||||
% Technically, the merchant could still
|
||||
%use an anonymous communication channel to communicate with the mint.
|
||||
%However, in order to receive the traditional currency the mint will
|
||||
%require (SEPA) account details for the deposit.
|
||||
|
||||
%As both the initial transaction between the customer and the mint as
|
||||
%well as the transactions between the merchant and the mint do not have
|
||||
%to be done anonymously, there might be a formal business contract
|
||||
%between the customer and the mint and the merchant and the mint. Such
|
||||
%a contract may provide customers and merchants some assurance that
|
||||
%they will actually receive the traditional currency from the mint
|
||||
%given cryptographic proof about the validity of the transaction(s).
|
||||
%However, given the business overheads for establishing such contracts
|
||||
%and the natural goal for the mint to establish a reputation and to
|
||||
%minimize cost, it is more likely that the mint will advertise its
|
||||
%external auditors and proven reserves and thereby try to convince
|
||||
%customers and merchants to trust it without a formal contract.
|
||||
|
||||
|
||||
\subsection{Coins}
|
||||
|
||||
A \emph{coin} is a digital token which derives its financial value
|
||||
from a signature on the coin's identifier by a mint. The mint is
|
||||
expected to have multiple {\em coin signing key} pairs available for
|
||||
signing, each representing a different coin denomination.
|
||||
|
||||
The coin signing keys have an expiration date (typically measured in
|
||||
years), and coins signed with a coin signing key must be spent (or
|
||||
exchanged for new coins) before that expiration date. This allows the
|
||||
mint to limit the amount of state it needs to keep to detect
|
||||
double spending attempts. Furthermore, the mint is expected to use each coin
|
||||
signing key only for a limited number of coins, for example by
|
||||
limiting its use to sign coins to a week or a month. That way, if the
|
||||
private coin signing key were to be compromised, the mint can detect
|
||||
this once more coins are redeemed than the total that was signed into
|
||||
existence using the respective coin signing key. In this case, the
|
||||
mint can allow the original set of customers to exchange the coins
|
||||
that were signed with the compromised private key, while refusing
|
||||
further transactions from merchants if they involve those coins. As a
|
||||
result, the financial damage of loosing a private signing key can be
|
||||
limited to at most twice the amount originally signed with that key.
|
||||
To ensure that the mint does not enable deanonymization of users by
|
||||
signing each coin with a fresh coin signing key, the mint must
|
||||
publicly announce the coin signing keys in advance. Those
|
||||
announcements are expected to be signed with an off-line long-term
|
||||
private {\em master signing key} of the mint and possibly the auditor.
|
||||
|
||||
Before a customer can withdraw a coin from the mint, he has to pay the
|
||||
mint the value of the coin, as well as processing fees. This is done
|
||||
using other means of payments, such as SEPA transfers~\cite{sepa}.
|
||||
The subject line of the transfer must contains {\em withdrawal
|
||||
authorization key}, a public key for digital signatures generated by
|
||||
the customer. When the mint receives a transfer with a public key in
|
||||
the subject, it adds the funds to a {\em reserve} identified by the
|
||||
withdrawl authorization key. By signing the withdrawl messages using
|
||||
the withdrawl authorization key, the customer can prove to the mint
|
||||
that he is authorized to withdraw anonymous digital coins from the
|
||||
reserve. The mint will record the withdrawl messages with the reserve
|
||||
record as proof that the anonymous digital coin was created for the
|
||||
correct customer.
|
||||
|
||||
After a coin is minted, the customer is the only entity that knows the
|
||||
private key of the coin, making him the \emph{owner} of the coin. The
|
||||
coin can be identified by the mint by its public key; however, due to
|
||||
the use of blind signatures, the mint does not learn the public key
|
||||
during the minting process. Knowledge of the private key of the coin
|
||||
enables the owner to spent the coin. If the private key is shared
|
||||
with others, they also become owners of the coin.
|
||||
|
||||
\subsection{Coin spending}
|
||||
|
||||
To spent a coin, the coin's owner needs to sign a {\em deposit
|
||||
request} specifying the amount, the merchant's account information
|
||||
and a {\em business transaction-specific hash} using the coin's
|
||||
private key. A merchant can then transfer this permission of the
|
||||
coin's owner to the mint to obtain the amount in traditional currency.
|
||||
If the customer is cheating and the coin was already spent, the mint
|
||||
provides cryptographic proof of the fraud to the merchant, who will
|
||||
then refuse the transaction.
|
||||
% The mint is typically expected
|
||||
%to transfer the funds to the merchant using a SEPA transfer or similar
|
||||
%methods appropriate to the domain of the traditional currency.
|
||||
|
||||
%The mint needs to ensure that a coin can only be spent once. This is
|
||||
%done by storing the public keys of all deposited coins (together with
|
||||
%the deposit request and the owner's signature confirming the
|
||||
%transaction). The mint's state can be limited as coins signed with
|
||||
%expired coin sigining keys do not have to be retained.
|
||||
|
||||
\paragraph{Partial spending.}
|
||||
|
||||
To allow exact payments without requiring the customer to keep a large
|
||||
amount of ``change'' in stock, the payment systems allows partial
|
||||
spending of coins. Consequently, the mint the must not only store the
|
||||
identifiers of spent coins, but also the fraction of the coin that has
|
||||
been spent.
|
||||
|
||||
%\paragraph{Online checks.}
|
||||
%
|
||||
%For secure transactions (non-microdonations), the merchant is expected
|
||||
%to perform an online check to detect double-spending. In the simplest
|
||||
%case, the merchant simply directly confirms the validity of the
|
||||
%deposit permission signed by the coin's owner with the mint, and then
|
||||
%proceeds with the contract.
|
||||
|
||||
\paragraph{Incremental payments.}
|
||||
|
||||
For services that include pay-as-you-go billing, customers can over
|
||||
time sign deposit permissions for an increasing fraction of the value
|
||||
of a coin to be paid to a particular merchant. As checking with the
|
||||
mint for each increment might be expensive, the coin's owner can
|
||||
instead sign a {\em lock permission}, which allows the merchant to get
|
||||
an exclusive right to redeem deposit permissions for the coin for a
|
||||
limited duration. The merchant uses the lock permission to determine
|
||||
if the coin has already been spent and to ensure that it cannot be
|
||||
spent by another merchant for the {\em duration} of the lock as
|
||||
specified in the lock permission. If the coin has been spent or is
|
||||
already locked, the mint provides the owner's deposit or locking
|
||||
request and signature to prove the attempted fraud by the customer.
|
||||
Otherwise, the mint locks the coin for the expected duration of the
|
||||
transaction (and remembers the lock permission). The merchant and the
|
||||
customer can then finalize the business transaction, possibly
|
||||
exchanging a series of incremental payment permissions for services.
|
||||
Finally, the merchant then redeems the coin at the mint before the
|
||||
lock permission expires to ensure that no other merchant spends the
|
||||
coin first.
|
||||
|
||||
|
||||
\paragraph{Probabilistic spending.}
|
||||
|
||||
Similar to Peppercoin, Taler supports probabilistic spending of coins to
|
||||
support cost-effective transactions for small amounts. Here, an
|
||||
ordinary transaction is performed based on the result of a biased coin
|
||||
flip with a probability related to the desired transaction amount in
|
||||
relation to the value of the coin. Unlike Peppercoin, in Taler either
|
||||
the merchant wins and the customer looses the coin, or the merchant
|
||||
looses and the customer keeps the coin. Thus, there is no opportunity
|
||||
for the merchant and the customer to conspire against the mint. To
|
||||
determine if the coin is to be transferred, merchant and customer
|
||||
execute a secure coin flipping protocol~\cite{blum1981}. The commit
|
||||
values are included in the business contract and are revealed after
|
||||
the contract has been signed using the private key of the coin. If
|
||||
the coin flip is decided in favor of the merchant, the merchant can
|
||||
redeem the coin at the mint.
|
||||
|
||||
One issue in this protocol is that the customer may use a worthless
|
||||
coin by offering a coin that has already been spent. This kind of
|
||||
fraud would only be detected if the customer actually lost the coin
|
||||
flip, and at this point the merchant might not be able to recover from
|
||||
the loss. A fradulent anonymous customer may run the protocol using
|
||||
already spent coins until the coin flip is in his favor. As with
|
||||
incremental spending, lock permissions could be used to ensure that
|
||||
the customer cannot defraud the merchant by offering a coin that has
|
||||
already been spent. However, as this means involving the mint even if
|
||||
the merchant looses the coin flip, such a scheme is unsuitable for
|
||||
microdonations as the transaction costs from involving the mint might
|
||||
be disproportionate to the value of the transaction, and thus with
|
||||
locking the probabilistic scheme has no advantage over simply using
|
||||
fractional payments.
|
||||
|
||||
Hence, Taler uses probabilistic transactions {\em without} the online
|
||||
double-spending detection. This enables the customer to defraud the
|
||||
merchant by paying with a coin that was already spent. However, as,
|
||||
by definition, such microdonations are for tiny amounts, the incentive
|
||||
for customers to pursue this kind of fraud is limited.
|
||||
|
||||
|
||||
\subsection{Refreshing Coins}
|
||||
|
||||
In the payment scenarios there are several cases where a customer will
|
||||
reveal the public key of a coin to a merchant, but not ultimately sign
|
||||
over the full value of the coin. If the customer then continues to
|
||||
use the remainder of the value of the coin in other transactions,
|
||||
merchants and the mint could link the various transactions as they all
|
||||
share the same public key for the coin.
|
||||
|
||||
Thus, the owner might want to exchange such a {\em dirty} coin for a
|
||||
{\em fresh} coin to ensure unlinkability of future transactions with
|
||||
the previous operation. Even if a coin is not dirty, the owner of a
|
||||
coin may want to exchange a coin if the respective coin signing key is
|
||||
about to expire. All of these operations are supported with the {\em
|
||||
coin refreshing protocol}, which allows the owner of a coin to
|
||||
exchange existing coins (or their remaining value) for fresh coins
|
||||
with a new public-private key pairs. Refreshing does not use the
|
||||
ordinary spending operation as the owner of a coin should not have to
|
||||
pay taxes on this operation. Because of this, the refreshing protocol
|
||||
must assure that owner stays the same. After all, the coin refreshing
|
||||
protocol must not be usable for transactions, as transactions in Taler
|
||||
must be taxable.
|
||||
|
||||
Thus, one main goal of the refreshing protocol is that the mint must
|
||||
not be able to link the fresh coin's public key to the public key of
|
||||
the dirty coin. The second main goal is to enable the mint to ensure
|
||||
that the owner of the dirty coin can determine the private key of the
|
||||
fresh coin. This way, refreshing cannot be used to construct a
|
||||
transaction --- the owner of the dirty coin remains in control of the
|
||||
fresh coin.
|
||||
|
||||
As with other operations, the refreshing protocol must also protect
|
||||
the mint from double-spending; similarly, the customer has to have
|
||||
cryptographic evidence if there is any misbehaviour by the mint.
|
||||
Finally, the mint may choose to charge a transaction fee for
|
||||
refreshing by reducing the value of the generated fresh coins
|
||||
in relation to the value of the melted coins.
|
||||
%Naturally, all such transaction fees should be clearly stated as part
|
||||
%of the business contract offered by the mint to customers and
|
||||
%merchants.
|
||||
|
||||
|
||||
\section{Taler's Cryptographic Protocols}
|
||||
|
||||
% In this section, we describe the protocols for Taler in detail.
|
||||
|
||||
For the sake of brevity, we do not specifically state that the
|
||||
recipient of a signed message always first checks that the signature
|
||||
is valid. Also, whenever a signed message is transmitted, it is
|
||||
assumed that the receiver is told the public key (or knows it from the
|
||||
context) and that the signature contains additional identification as
|
||||
to the purpose of the signature (such that it is not possible to
|
||||
use a signature from one protocol step in a different context).
|
||||
|
||||
When the mint signs messages (not coins), an {\em online message
|
||||
signing key} of the mint is used. The mint's long-term offline key
|
||||
is used to certify both the coin signing keys as well as the online
|
||||
message signing key of the mint. The mint's long-term offline key is
|
||||
assumed to be well-known to both customers and merchants, for example
|
||||
because it is certified by the auditors.
|
||||
|
||||
As we are dealing with financial transactions, we explicitly state
|
||||
whenever entities need to safely commit data to persistent storage.
|
||||
As long as those commitments persist, the protocol can be safely
|
||||
resumed at any step. Commitments to disk are cummulative, that is an
|
||||
additional commitment does not erase the previously committed
|
||||
information. Keys and thus coins always have a well-known expiration
|
||||
date; information committed to disk can be discarded after the
|
||||
expiration date of the respective public key. Customers can also
|
||||
discard information once the respective coins have been fully spent,
|
||||
and merchants may discard information once payments from the mint have
|
||||
been received (assuming records are also no longer needed for tax
|
||||
authorities). The mint's bank transfers dealing in traditional
|
||||
currency are expected to be recorded for tax authorities to ensure
|
||||
taxability.
|
||||
|
||||
\subsection{Withdrawal}
|
||||
|
||||
To withdraw anonymous digital coins, the customer performs the
|
||||
following interaction with the mint:
|
||||
|
||||
\begin{enumerate}
|
||||
\item The customer identifies a mint with an auditor-approved
|
||||
coin signing public-private key pair $K := (K_s, K_p)$
|
||||
and randomly generates:
|
||||
\begin{itemize}
|
||||
\item withdrawal key $W := (W_s,W_p)$ with private key $W_s$ and public key $W_p$,
|
||||
\item coin key $C := (C_s,C_p)$ with private key $C_s$ and public key $C_p$,
|
||||
\item blinding factor $b$,
|
||||
\end{itemize}
|
||||
and commits $\langle W, C, b \rangle$ to disk.
|
||||
\item The customer transfers an amount of money corresponding to (at least) $K_p$ to the mint, with $W_p$ in the subject line of the transaction.
|
||||
\item The mint receives the transaction and credits the $W_p$ reserve with the respective amount in its database.
|
||||
\item The customer sends $S_W(E_b(C_p))$ to the mint to request withdrawl of $C$; here, $E_b$ denotes Chaum-style blinding with blinding factor $b$.
|
||||
\item The mint checks if the same withdrawl request was issued before; in this case, it sends $S_{K}(E_b(C_p))$ to the customer.\footnote{Here $S_K$
|
||||
denotes a Chaum-style blind signature with private key $K_s$.}
|
||||
If this is a fresh withdrawl request, the mint performs the following transaction:
|
||||
\begin{enumerate}
|
||||
\item checks if the reserve $W_p$ has sufficient funds for a coin of value corresponding to $K_p$
|
||||
\item stores the withdrawl request $\langle S_W(E_b(C_p)), S_K(E_b(C_p)) \rangle$ in its database for future reference,
|
||||
\item deducts the amount corresponding to $K_p$ from the reserve,
|
||||
\item and sends $S_{K}(E_b(C_p))$ to the customer.
|
||||
\end{enumerate}
|
||||
If the guards for the transaction fail, the mint sends an descriptive error back to the customer,
|
||||
with proof that it operated correctly (i.e. by showing the transaction history for the reserve).
|
||||
\item The customer computes (and verifies) the unblind signature $S_K(C_p) = D_b(S_K(E_b(C_p)))$.
|
||||
The customer writes $\langle S_K(C_p), C_s \rangle$ to disk (effectively adding the coin to the
|
||||
local wallet) for future use.
|
||||
\end{enumerate}
|
||||
|
||||
\subsection{Exact, partial and incremental spending}
|
||||
|
||||
A customer can spend coins at a merchant, under the condition that the
|
||||
merchant trusts the mint that minted the coin. Merchants are
|
||||
identified by their public key $M := (M_s, M_p)$, which must be known
|
||||
to the customer apriori.
|
||||
|
||||
The following steps describe the protocol between customer, merchant and mint
|
||||
for a transaction involving a coin $C := (C_s, C_p)$ which is previously signed
|
||||
by a mint's denomination key $K$, i.e. the customer posses
|
||||
$\widetilde{C} := S_K(C_p)$:
|
||||
|
||||
\begin{enumerate}
|
||||
\item\label{offer} The merchant sends an \emph{offer:} $\langle S_M(m, f),
|
||||
\vec{D} \rangle$ containing the price of the offer $f$, a transaction
|
||||
ID $m$ and the list of mints $D_1, \ldots, D_n$ accepted by the merchant
|
||||
where each $D_i$ is a mint's public key.
|
||||
\item\label{lock} The customer must possess or acquire a coin minted by a mint that is
|
||||
accepted by the merchant, i.e. $K$ should be publicly signed by some $D_i
|
||||
\in \{D_1, D_2, \ldots, D_n\}$, and has a value $\geq f$.
|
||||
|
||||
Customer then generates a \emph{lock-permission} $\mathcal{L} :=
|
||||
S_c(\widetilde{C}, t, m, f, M_p)$ where $t$ specifies the time until which the
|
||||
lock is valid and sends $\langle \mathcal{L}, D_i\rangle$ to the merchant,
|
||||
where $D_i$ is the mint which signed $K$.
|
||||
\item The merchant asks the mint to apply the lock by sending $\langle
|
||||
\mathcal{L} \rangle$ to the mint.
|
||||
\item The mint validates $\widetilde{C}$ and detects double spending if there is
|
||||
a lock-permission record $S_c(\widetilde{C}, t', m', f', M_p')$ where $(t',
|
||||
m', f', M_p') \neq (t, m, f, M_p)$ or a \emph{deposit-permission} record for
|
||||
$C$ and sends it to the merchant, who can then use it prove to the customer
|
||||
and subsequently ask the customer to issue a new lock-permission.
|
||||
|
||||
If double spending is not found, the mint commits $\langle \mathcal{L} \rangle$ to disk
|
||||
and notifies the merchant that locking was successful.
|
||||
\item\label{contract} The merchant creates a digitally signed contract
|
||||
$\mathcal{A} := S_M(m, f, a, H(p, r))$ where $a$ is data relevant to the contract
|
||||
indicating which services or goods the merchant will deliver to the customer, and $p$ is the
|
||||
merchant's payment information (e.g. his IBAN number) and $r$ is an random nounce.
|
||||
The merchant commits $\langle \mathcal{A} \rangle$ to disk and sends it to the customer.
|
||||
\item The customer creates a
|
||||
\emph{deposit-permission} $\mathcal{D} := S_c(\widetilde{C}, f, m, M_p, H(a), H(p, r))$, commits
|
||||
$\langle \mathcal{A}, \mathcal{D} \rangle$ to disk and sends $\mathcal{D}$ to the merchant.
|
||||
\item\label{invoice_paid} The merchant commits the received $\langle \mathcal{D} \rangle$ to disk.
|
||||
\item The merchant gives $(\mathcal{D}, p, r)$ to the mint, revealing his
|
||||
payment information.
|
||||
\item The mint verifies $(\mathcal{D}, p, r)$ for its validity. A
|
||||
\emph{deposit-permission} for a coin $C$ is valid if:
|
||||
\begin{itemize}
|
||||
\item $C$ is not refreshed already
|
||||
\item there exists no other \emph{deposit-permission} on disk for \\
|
||||
$\mathcal{D'} := S_c(\widetilde{C}, f', m', M_p', H(a'), H(p', r'))$ for $C$
|
||||
such that \\ $(f', m',M_p', H(a')) \neq (f, m, M_p, H(a))$
|
||||
\item $H(p, r) := H(p', r')$
|
||||
\end{itemize}
|
||||
If $C$ is valid and no other \emph{deposit-permission} for $C$ exists on disk, the
|
||||
mint does the following:
|
||||
\begin{enumerate}
|
||||
\item if a \emph{lock-permission} exists for $C$, it is deleted from disk
|
||||
\item\label{transfer} transfers an amount of $f$ to the merchant's bank account
|
||||
given in $p$. The subject line of the transaction to $p$ must contain
|
||||
$H(\mathcal{D})$.
|
||||
\item $\langle \mathcal{D}, p, r \rangle$ is commited to disk.
|
||||
\end{enumerate}
|
||||
If the deposit record $\langle \mathcal{D}, p, r \rangle$ already exists,
|
||||
the mint sends it to the merchant, but does not transfer money to $p$ again.
|
||||
\end{enumerate}
|
||||
|
||||
To facilitate incremental spending of a coin $C$ in a single transaction, the
|
||||
merchant makes an offer in Step~\ref{offer} with a maximum amount $f_{max}$ he
|
||||
is willing to charge in this transaction from the coin $C$. After obtaining the
|
||||
lock on $C$ for $f_{max}$, the merchant makes a contract in Step~\ref{contract}
|
||||
with an amount $f \leq f_{max}$. The protocol follows with the following steps
|
||||
repeated after Step~\ref{invoice_paid} whenever the merchant wants to charge an
|
||||
incremental amount up to $f_{max}$:
|
||||
|
||||
\begin{enumerate}
|
||||
\setcounter{enumi}{4}
|
||||
\item The merchant generates a new contract $ \mathcal{A}' := S_M(m, f', a', H(p,
|
||||
r)) $ after obtaining the deposit-permission for a previous contract. Here
|
||||
$f'$ is the accumulated sum the merchant is charging the customer, of which
|
||||
the merchant has received a deposit-permission for $f$ from the previous
|
||||
contract \textit{i.e.}~$f <f' \leq f_{max}$. Similarly $a'$ is the new
|
||||
contract data appended to older contract data $a$.
|
||||
The merchant commits $\langle \mathcal{A}' \rangle$ to disk and sends it to the customer.
|
||||
\item Customer commits $\langle \mathcal{A}' \rangle$ to disk, creates
|
||||
$\mathcal{D}' := S_c(\widetilde{C}, f', m, M_p, H(a'), H(p, r))$, commits
|
||||
$\langle \mathcal{D'} \rangle$ and sends it to the merchant.
|
||||
\item The merchant commits the received $\langle \mathcal{D'} \rangle$ and
|
||||
deletes the older $\mathcal{D}$
|
||||
\end{enumerate}
|
||||
|
||||
%Figure~\ref{fig:spending_protocol_interactions} summarizes the interactions of the
|
||||
%coin spending protocol.
|
||||
|
||||
For transactions with multiple coins, the steps of the protocol are executed in
|
||||
parallel for each coin.
|
||||
|
||||
During the time a coin is locked, it may not be spent at a
|
||||
different merchant. To make the storage costs of the mint more predictable,
|
||||
only one lock per coin can be active at any time, even if the lock only covers a
|
||||
fraction of the coin's denomination. The mint will delete the locks when they
|
||||
expire. Thus the coins can be reused once their locks expire. However, doing
|
||||
so may link the new transaction to older transaction.
|
||||
|
||||
Similarly, if a transaction is aborted after Step 2, subsequent transactions
|
||||
with the same coin can be linked to the coin, but not directly to the coin's
|
||||
owner. The same applies to partially spent coins. To unlink subsequent
|
||||
transactions from a coin, the customer has to execute the coin refreshing
|
||||
protocol with the mint.
|
||||
|
||||
%\begin{figure}[h]
|
||||
%\centering
|
||||
%\begin{tikzpicture}
|
||||
%
|
||||
%\tikzstyle{def} = [node distance= 1em, inner sep=.5em, outer sep=.3em];
|
||||
%\node (origin) at (0,0) {};
|
||||
%\node (offer) [def,below=of origin]{make offer (merchant $\rightarrow$ customer)};
|
||||
%\node (A) [def,below=of offer]{permit lock (customer $\rightarrow$ merchant)};
|
||||
%\node (B) [def,below=of A]{apply lock (merchant $\rightarrow$ mint)};
|
||||
%\node (C) [def,below=of B]{confirm (or refuse) lock (mint $\rightarrow$ merchant)};
|
||||
%\node (D) [def,below=of C]{sign contract (merchant $\rightarrow$ customer)};
|
||||
%\node (E) [def,below=of D]{permit deposit (customer $\rightarrow$ merchant)};
|
||||
%\node (F) [def,below=of E]{make deposit (merchant $\rightarrow$ mint)};
|
||||
%\node (G) [def,below=of F]{transfer confirmation (mint $\rightarrow$ merchant)};
|
||||
%
|
||||
%\tikzstyle{C} = [color=black, line width=1pt]
|
||||
%\draw [->,C](offer) -- (A);
|
||||
%\draw [->,C](A) -- (B);
|
||||
%\draw [->,C](B) -- (C);
|
||||
%\draw [->,C](C) -- (D);
|
||||
%\draw [->,C](D) -- (E);
|
||||
%\draw [->,C](E) -- (F);
|
||||
%\draw [->,C](F) -- (G);
|
||||
%
|
||||
%\draw [->,C, bend right, shorten <=2mm] (E.east)
|
||||
% to[out=-135,in=-45,distance=3.8cm] node[left] {aggregate} (D.east);
|
||||
%\end{tikzpicture}
|
||||
%\caption{Interactions between a customer, merchant and mint in the coin spending
|
||||
% protocol}
|
||||
%\label{fig:spending_protocol_interactions}
|
||||
%\end{figure}
|
||||
|
||||
|
||||
\subsection{Probabilistic spending}
|
||||
|
||||
The following steps are executed for microdonations with upgrade probability $p$:
|
||||
\begin{enumerate}
|
||||
\item The merchant sends an offer to the customer.
|
||||
\item The customer sends a commitment $H(r_c)$ to a random
|
||||
value $r_c \in [0,2^R)$, where $R$ is a system parameter.
|
||||
\item The merchant sends random $r_m \in [0,2^R)$ to the customer.
|
||||
\item The customer computes $p' := (|r_c - r_m|) / (2^R)$.
|
||||
If $p' < p$, the customer sends a coin with deposit-permission to the merchant.
|
||||
Otherwise, the customer sends $r_c$ to the merchant.
|
||||
\item The merchant deposits the coin, or checks if $r_c$ is consistent
|
||||
with $H(r_c)$.
|
||||
\end{enumerate}
|
||||
|
||||
\subsection{Refreshing}
|
||||
|
||||
The following protocol is executed in order to refresh a coin $C'$ of denomination $K$ to
|
||||
a fresh coin $\widetilde{C}$ with the same denomination. In the protocol, $\kappa \ge 3$ is a security parameter.
|
||||
|
||||
\begin{enumerate}
|
||||
\item For each $i = 1,\ldots,\kappa$, the customer
|
||||
\begin{itemize}
|
||||
\item randomly generates transfer key $T^{(i)} := \left(t^{(i)}_s,T^{(i)}_p\right)$ where $T^{(i)}_p := t^{(i)}_s \cdot G$,
|
||||
\item randomly generates coin key pair $C^{(i)} := \left(c_s^{(i)}, C_p^{(i)}\right)$ where $C^{(i)}_p := c^{(i)}_s \cdot G$,
|
||||
\item randomly generates blinding factors $b_i$,
|
||||
\item computes $E_i := E_{K_i}\left(c_s^{(i)}, b_i\right)$ where $K_i := c'_s \cdot T_p^{(i)}$ (The encryption key $K_i$ is
|
||||
computed by multiplying the private key $c'_s$ of the original coin with the point on the curve
|
||||
that represents the public key of the transfer key $T^{(i)}$.),
|
||||
\end{itemize}
|
||||
and commits $\langle C', \vec{T}, \vec{C}, \vec{b} \rangle$ to disk.
|
||||
\item The customer computes $B_i := E_{b_i}(C^{(i)}_p)$ and sends commitments
|
||||
$S_{C'}(\vec{E}, \vec{B}, \vec{T}))$ for $i=1,\ldots,\kappa$ to the mint;
|
||||
here $E_{b_i}$ denotes Chaum-style blinding with blinding factor $b_i$.
|
||||
\item The mint generates a random $\gamma$ with $1 \le \gamma \le \kappa$ and
|
||||
marks $C'_p$ as spent by committing
|
||||
$\langle C', \gamma, S_{C'}(\vec{E}, \vec{B}, \vec{T}) \rangle$ to disk
|
||||
\item The mint sends $S_K(C'_p, \gamma)$ to the customer.\footnote{Instead of $K$, it is also
|
||||
possible to use any equivalent mint signing key known to the customer here, as $K$ merely
|
||||
serves as proof to the customer that the mint selected this particular $\gamma$.}
|
||||
\item The customer commits $\langle C', S_K(C'_p, \gamma) \rangle$ to disk.
|
||||
\item The customer computes $\mathfrak{R} := \left(t_s^{(i)}, C_p^{(i)}, b_i\right)_{i \ne \gamma}$
|
||||
and sends $S_{C'}(\mathfrak{R})$ to the mint.
|
||||
\item \label{step:refresh-ccheck} The mint checks whether $\mathfrak{R}$ is consistent with the commitments;
|
||||
specifically, it computes for $i \not= \gamma$:
|
||||
\begin{itemize}
|
||||
\item $\overline{K}_i := t_s^{(i)} \cdot C_p'$,
|
||||
\item $(\overline{c}_s^{(i)}, \overline{b}_i) := D_{\overline{K}_i}(E_i)$,
|
||||
\item $\overline{C}^{(i)}_p := \overline{c}_s^{(i)} \cdot G$,
|
||||
\item $\overline{B}_i := E_{b_i}(C_p^{(i)})$,
|
||||
\item $\overline{T}_i := t_s^{(i)} G$,
|
||||
\end{itemize}
|
||||
and checks if $\overline{C}^{(i)}_p = C^{(i)}_p$ and $H(E_i, \overline{B}_i, \overline{T}^{(i)}_p) = H(E_i, B_i, T^{(i)}_p)$
|
||||
and $\overline{T}_i = T_i$.
|
||||
|
||||
\item \label{step:refresh-done} If the commitments were consistent, the mint sends the blind signature
|
||||
$\widetilde{C} := S_{K}(B_\gamma)$ to the customer.
|
||||
Otherwise, the mint responds with an error and confiscates the value of $C'$,
|
||||
committing $\langle C', \gamma, S_{C'}(\mathfrak{R}) \rangle$ to disk as proof for the attempted fraud.
|
||||
\end{enumerate}
|
||||
|
||||
%\subsection{N-to-M Refreshing}
|
||||
%
|
||||
%TODO: Explain, especially subtleties regarding session key / the spoofing attack that requires signature.
|
||||
|
||||
\subsection{Linking}
|
||||
|
||||
For a coin that was successfully refreshed, the mint responds to
|
||||
a request $S_{C'}(\mathtt{link})$ with $(T^{(\gamma)}_p$, $E_{\gamma}, \widetilde{C})$.
|
||||
|
||||
This allows the owner of the old coin to also obtain the private key
|
||||
of the new coin, even if the refreshing protocol was illicitly
|
||||
executed by another party who learned $C'_s$ from the old owner.
|
||||
|
||||
|
||||
\section{Discussion}
|
||||
|
||||
\subsection{Offline Payments}
|
||||
|
||||
Chaum's original proposals for anonymous digital cash avoided the
|
||||
locking and online spending steps detailed in this proposal by
|
||||
providing a means to deanonymize customers involved in
|
||||
double-spending. We believe that this is problematic as the mint or
|
||||
the merchant will then still need out-of-band means to recover funds
|
||||
from the customer, which may be impossible in practice. In contrast,
|
||||
in our design only the mint may try to defraud the other participants
|
||||
and disappear. While this is still a risk, this is likely manageable,
|
||||
especially compared to recovering funds via the court system from
|
||||
customers.
|
||||
|
||||
|
||||
\subsection{Bona-fide microdonations}
|
||||
|
||||
Evidently the customer can ``cheat'' by aborting the transaction in
|
||||
Step 3 of the microdonation protocol if the outcome is unfavourable ---
|
||||
and repeat until he wins. This is why Taler is suitable for
|
||||
microdonations --- where the customer voluntarily contributes ---
|
||||
and not for micropayments.
|
||||
|
||||
Naturally, if the donations requested are small, the incentive to
|
||||
cheat for minimal gain should be quite low. Payment software could
|
||||
embrace this fact by providing an appeal to conscience in form of an
|
||||
option labeled ``I am unethical and want to cheat'', which executes
|
||||
the dishonest version of the payment protocol.
|
||||
|
||||
If an organization detects that it cannot support itself with
|
||||
microdonations, it can always choose to switch to the macropayment
|
||||
system with slightly higher transaction costs to remain in business.
|
||||
|
||||
\subsection{Merchant Tax Audits}
|
||||
|
||||
For a tax audit on the merchant, the mint includes the business
|
||||
transaction-specific hash in the transfer of the traditional
|
||||
currency. A tax auditor can then request the merchant to reveal
|
||||
(meaningful) details about the business transaction ($\mathcal{D}$,
|
||||
$a$, $p$, $r$), including proof that applicable taxes were paid.
|
||||
|
||||
If a merchant is not able to provide theses values, he can be punished
|
||||
in relation to the amount transferred by the traditional currency
|
||||
transfer.
|
||||
|
||||
|
||||
\section{Future Work}
|
||||
|
||||
%The legal status of the system needs to be investigated in the various
|
||||
%legal systems of the world. However, given that the system enables
|
||||
%taxation and is able to impose withdrawl limits and thus is not
|
||||
%suitable for money laundering, we are optimistic that states will find
|
||||
%the design desirable.
|
||||
|
||||
We did not yet perform performance measurements for the various
|
||||
operations. However, we are pretty sure that the computational and
|
||||
bandwidth cost for transactions described in this paper is likely
|
||||
small compared to other business costs for the mint. We expect costs
|
||||
within the system to be dominated by the (replicated, transactional)
|
||||
database. However, these expenses are again likely small in relation
|
||||
to the business cost of currency transfers using traditional banking.
|
||||
Here, mint operators should be able to reduce their expenses by
|
||||
aggregating multiple transfers to the same merchant.
|
||||
|
||||
|
||||
\section{Conclusion}
|
||||
|
||||
We have presented an efficient electronic payment system that
|
||||
simultaneously addresses the conflicting objectives created by the
|
||||
citizen's need for privacy and the state's need for taxation. The
|
||||
coin refreshing protocol makes the design flexible and enables a
|
||||
variety of payment methods. The libre implementation and open
|
||||
protocol may finally enable modern society to upgrade to proper
|
||||
electronic wallets with efficient, secure and privacy-preserving
|
||||
transactions.
|
||||
|
||||
\bibliographystyle{alpha}
|
||||
\bibliography{taler}
|
||||
\end{document}
|
9
src/.gitignore
vendored
Normal file
9
src/.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
*.o
|
||||
*.deps
|
||||
*.libs
|
||||
*.lo
|
||||
*.la
|
||||
*.log
|
||||
*.trs
|
||||
*/__pycache__
|
||||
test-*
|
2
src/Makefile.am
Normal file
2
src/Makefile.am
Normal file
@ -0,0 +1,2 @@
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src/include
|
||||
SUBDIRS = include util mint
|
7
src/include/Makefile.am
Normal file
7
src/include/Makefile.am
Normal file
@ -0,0 +1,7 @@
|
||||
EXTRA_DIST = \
|
||||
platform.h \
|
||||
taler_blind.h \
|
||||
taler_signatures.h \
|
||||
taler_types.h \
|
||||
taler_util.h \
|
||||
taler_rsa.h
|
56
src/include/platform.h
Normal file
56
src/include/platform.h
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Chrisitan Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file include/platform.h
|
||||
* @brief This file contains the includes and definitions which are used by the
|
||||
* rest of the modules
|
||||
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||
*/
|
||||
|
||||
#ifndef PLATFORM_H_
|
||||
#define PLATFORM_H_
|
||||
|
||||
/* Include our configuration header */
|
||||
#ifndef HAVE_USED_CONFIG_H
|
||||
# define HAVE_USED_CONFIG_H
|
||||
# ifdef HAVE_CONFIG_H
|
||||
# include "taler_config.h"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#if (GNUNET_EXTRA_LOGGING >= 1)
|
||||
#define VERBOSE(cmd) cmd
|
||||
#else
|
||||
#define VERBOSE(cmd) do { break; }while(0)
|
||||
#endif
|
||||
|
||||
/* Include the features available for GNU source */
|
||||
#define _GNU_SOURCE
|
||||
|
||||
/* Include GNUnet's platform file */
|
||||
#include <gnunet/platform.h>
|
||||
|
||||
/* Do not use shortcuts for gcrypt mpi */
|
||||
#define GCRYPT_NO_MPI_MACROS 1
|
||||
|
||||
/* Do not use deprecated functions from gcrypt */
|
||||
#define GCRYPT_NO_DEPRECATED 1
|
||||
|
||||
#endif /* PLATFORM_H_ */
|
||||
|
||||
/* end of platform.h */
|
132
src/include/taler_db_lib.h
Normal file
132
src/include/taler_db_lib.h
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file include/taler_db_lib.h
|
||||
* @brief helper functions for DB interactions
|
||||
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||
* @author Florian Dold
|
||||
*/
|
||||
|
||||
#ifndef TALER_DB_LIB_H_
|
||||
#define TALER_DB_LIB_H_
|
||||
|
||||
#include <libpq-fe.h>
|
||||
#include "taler_util.h"
|
||||
|
||||
#define TALER_DB_QUERY_PARAM_END { NULL, 0, 0 }
|
||||
#define TALER_DB_QUERY_PARAM_PTR(x) { (x), sizeof (*(x)), 1 }
|
||||
#define TALER_DB_QUERY_PARAM_PTR_SIZED(x, s) { (x), (s), 1 }
|
||||
|
||||
|
||||
#define TALER_DB_RESULT_SPEC_END { NULL, 0, NULL }
|
||||
#define TALER_DB_RESULT_SPEC(name, dst) { (void *) (dst), sizeof (*(dst)), (name) }
|
||||
#define TALER_DB_RESULT_SPEC_SIZED(name, dst, s) { (void *) (dst), (s), (name) }
|
||||
|
||||
|
||||
/**
|
||||
* Description of a DB query parameter.
|
||||
*/
|
||||
struct TALER_DB_QueryParam
|
||||
{
|
||||
/**
|
||||
* Data or NULL
|
||||
*/
|
||||
const void *data;
|
||||
/**
|
||||
* Size of 'data'
|
||||
*/
|
||||
size_t size;
|
||||
/**
|
||||
* Non-null if this is not the last parameter.
|
||||
* This allows for null as sentinal value.
|
||||
*/
|
||||
int more;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Description of a DB result cell.
|
||||
*/
|
||||
struct TALER_DB_ResultSpec
|
||||
{
|
||||
/**
|
||||
* Destination for the data.
|
||||
*/
|
||||
void *dst;
|
||||
|
||||
/**
|
||||
* Allowed size for the data.
|
||||
*/
|
||||
size_t dst_size;
|
||||
|
||||
/**
|
||||
* Field name of the desired result.
|
||||
*/
|
||||
char *fname;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Execute a prepared statement.
|
||||
*/
|
||||
PGresult *
|
||||
TALER_DB_exec_prepared (PGconn *db_conn,
|
||||
const char *name,
|
||||
const struct TALER_DB_QueryParam *params);
|
||||
|
||||
|
||||
/**
|
||||
* Extract results from a query result according to the given specification.
|
||||
* If colums are NULL, the destination is not modified, and GNUNET_NO
|
||||
* is returned.
|
||||
*
|
||||
* @return
|
||||
* GNUNET_YES if all results could be extracted
|
||||
* GNUNET_NO if at least one result was NULL
|
||||
* GNUNET_SYSERR if a result was invalid (non-existing field)
|
||||
*/
|
||||
int
|
||||
TALER_DB_extract_result (PGresult *result, struct TALER_DB_ResultSpec *rs, int row);
|
||||
|
||||
|
||||
int
|
||||
TALER_DB_field_isnull (PGresult *result,
|
||||
int row,
|
||||
const char *fname);
|
||||
|
||||
|
||||
int
|
||||
TALER_DB_extract_amount_nbo (PGresult *result,
|
||||
int row,
|
||||
const char *val_name,
|
||||
const char *frac_name,
|
||||
const char *curr_name,
|
||||
struct TALER_AmountNBO *r_amount_nbo);
|
||||
|
||||
|
||||
int
|
||||
TALER_DB_extract_amount (PGresult *result,
|
||||
int row,
|
||||
const char *val_name,
|
||||
const char *frac_name,
|
||||
const char *curr_name,
|
||||
struct TALER_Amount *r_amount);
|
||||
|
||||
#endif /* TALER_DB_LIB_H_ */
|
||||
|
||||
/* end of include/taler_db_lib.h */
|
101
src/include/taler_json_lib.h
Normal file
101
src/include/taler_json_lib.h
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file include/taler_json_lib.h
|
||||
* @brief helper functions for JSON processing using libjansson
|
||||
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||
*/
|
||||
|
||||
#ifndef TALER_JSON_LIB_H_
|
||||
#define TALER_JSON_LIB_H_
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
|
||||
/**
|
||||
* Convert a TALER amount to a JSON
|
||||
* object.
|
||||
*
|
||||
* @param amount the amount
|
||||
* @return a json object describing the amount
|
||||
*/
|
||||
json_t *
|
||||
TALER_JSON_from_amount (struct TALER_Amount amount);
|
||||
|
||||
|
||||
/**
|
||||
* Convert absolute timestamp to a json string.
|
||||
*
|
||||
* @param the time stamp
|
||||
* @return a json string with the timestamp in @a stamp
|
||||
*/
|
||||
json_t *
|
||||
TALER_JSON_from_abs (struct GNUNET_TIME_Absolute stamp);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Convert binary data to a JSON string
|
||||
* with the base32crockford encoding.
|
||||
*
|
||||
* @param data binary data
|
||||
* @param size size of @a data in bytes
|
||||
* @return json string that encodes @a data
|
||||
*/
|
||||
json_t *
|
||||
TALER_JSON_from_data (const void *data, size_t size);
|
||||
|
||||
|
||||
/**
|
||||
* Parse given JSON object to Amount
|
||||
*
|
||||
* @param json the json object representing Amount
|
||||
* @param r_amount where the amount has to be written
|
||||
* @return GNUNET_OK upon successful parsing; GNUNET_SYSERR upon error
|
||||
*/
|
||||
int
|
||||
TALER_JSON_to_amount (json_t *json,
|
||||
struct TALER_Amount *r_amount);
|
||||
|
||||
/**
|
||||
* Parse given JSON object to absolute time.
|
||||
*
|
||||
* @param json the json object representing absolute time in seconds
|
||||
* @param r_abs where the time has to be written
|
||||
* @return GNUNET_OK upon successful parsing; GNUNET_SYSERR upon error
|
||||
*/
|
||||
int
|
||||
TALER_JSON_to_abs (json_t *json,
|
||||
struct GNUNET_TIME_Absolute *r_abs);
|
||||
|
||||
/**
|
||||
* Parse given JSON object to data
|
||||
*
|
||||
* @param json the json object representing data
|
||||
* @param out the pointer to hold the parsed data.
|
||||
* @param out_size the size of r_data.
|
||||
* @return GNUNET_OK upon successful parsing; GNUNET_SYSERR upon error
|
||||
*/
|
||||
int
|
||||
TALER_JSON_to_data (json_t *json,
|
||||
void *out,
|
||||
size_t out_size);
|
||||
|
||||
|
||||
#endif /* TALER_JSON_LIB_H_ */
|
||||
|
||||
/* End of taler_json_lib.h */
|
119
src/include/taler_microhttpd_lib.h
Normal file
119
src/include/taler_microhttpd_lib.h
Normal file
@ -0,0 +1,119 @@
|
||||
|
||||
|
||||
#ifndef TALER_MICROHTTPD_LIB_H_
|
||||
#define TALER_MICROHTTPD_LIB_H_
|
||||
|
||||
|
||||
#include <microhttpd.h>
|
||||
#include <jansson.h>
|
||||
|
||||
|
||||
/**
|
||||
* Constants for JSON navigation description.
|
||||
*/
|
||||
enum
|
||||
{
|
||||
/**
|
||||
* Access a field.
|
||||
* Param: const char *
|
||||
*/
|
||||
JNAV_FIELD,
|
||||
/**
|
||||
* Access an array index.
|
||||
* Param: int
|
||||
*/
|
||||
JNAV_INDEX,
|
||||
/**
|
||||
* Return base32crockford encoded data of
|
||||
* constant size.
|
||||
* Params: (void *, size_t)
|
||||
*/
|
||||
JNAV_RET_DATA,
|
||||
/**
|
||||
* Return base32crockford encoded data of
|
||||
* variable size.
|
||||
* Params: (void **, size_t *)
|
||||
*/
|
||||
JNAV_RET_DATA_VAR,
|
||||
/**
|
||||
* Return a json object, which must be
|
||||
* of the given type (JSON_* type constants,
|
||||
* or -1 for any type).
|
||||
* Params: (int, json_t **)
|
||||
*/
|
||||
JNAV_RET_TYPED_JSON
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Send JSON object as response. Decreases
|
||||
* the reference count of the JSON object.
|
||||
*
|
||||
* @param connection the MHD connection
|
||||
* @param json the json object
|
||||
* @param status_code the http status code
|
||||
* @return MHD result code (MHD_YES on success)
|
||||
*/
|
||||
int
|
||||
send_response_json (struct MHD_Connection *connection,
|
||||
json_t *json,
|
||||
unsigned int status_code);
|
||||
|
||||
|
||||
/**
|
||||
* Send a JSON object via an MHD connection,
|
||||
* specified with the JANSSON pack syntax (see json_pack).
|
||||
*
|
||||
* @param connection connection to send the JSON over
|
||||
* @param http_code HTTP status for the response
|
||||
* @param fmt format string for pack
|
||||
* @param ... varargs
|
||||
* @return MHD_YES on success or MHD_NO on error
|
||||
*/
|
||||
int
|
||||
request_send_json_pack (struct MHD_Connection *connection,
|
||||
unsigned int http_code,
|
||||
const char *fmt, ...);
|
||||
|
||||
|
||||
/**
|
||||
* Process a POST request containing a JSON object.
|
||||
*
|
||||
* @param connection the MHD connection
|
||||
* @param con_cs the closure (contains a 'struct Buffer *')
|
||||
* @param upload_data the POST data
|
||||
* @param upload_data_size the POST data size
|
||||
* @param json the JSON object for a completed request
|
||||
*
|
||||
* @returns
|
||||
* GNUNET_YES if json object was parsed
|
||||
* GNUNET_NO is request incomplete or invalid
|
||||
* GNUNET_SYSERR on internal error
|
||||
*/
|
||||
int
|
||||
process_post_json (struct MHD_Connection *connection,
|
||||
void **con_cls,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size,
|
||||
json_t **json);
|
||||
|
||||
|
||||
/**
|
||||
* Navigate through a JSON tree.
|
||||
*
|
||||
* Sends an error response if navigation is impossible (i.e.
|
||||
* the JSON object is invalid)
|
||||
*
|
||||
* @param connection the connection to send an error response to
|
||||
* @param root the JSON node to start the navigation at.
|
||||
* @param ... navigation specification (see JNAV_*)
|
||||
* @return GNUNET_YES if navigation was successful
|
||||
* GNUNET_NO if json is malformed, error response was generated
|
||||
* GNUNET_SYSERR on internal error
|
||||
*/
|
||||
int
|
||||
request_json_require_nav (struct MHD_Connection *connection,
|
||||
const json_t *root, ...);
|
||||
|
||||
#endif /* TALER_MICROHTTPD_LIB_H_ */
|
303
src/include/taler_mint_service.h
Normal file
303
src/include/taler_mint_service.h
Normal file
@ -0,0 +1,303 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file include/taler_mint_service.h
|
||||
* @brief C interface to the mint's HTTP API
|
||||
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||
*/
|
||||
|
||||
#ifndef _TALER_MINT_SERVICE_H
|
||||
#define _TALER_MINT_SERVICE_H
|
||||
|
||||
#include "taler_rsa.h"
|
||||
#include "taler_util.h"
|
||||
#include <jansson.h>
|
||||
|
||||
/**
|
||||
* Handle to this library context
|
||||
*/
|
||||
struct TALER_MINT_Context;
|
||||
|
||||
/**
|
||||
* Handle to the mint
|
||||
*/
|
||||
struct TALER_MINT_Handle;
|
||||
|
||||
/**
|
||||
* Mint's signature key
|
||||
*/
|
||||
struct TALER_MINT_SigningPublicKey
|
||||
{
|
||||
/**
|
||||
* The signing public key
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey key;
|
||||
|
||||
/**
|
||||
* Validity start time
|
||||
*/
|
||||
struct GNUNET_TIME_Absolute valid_from;
|
||||
|
||||
/**
|
||||
* Validity expiration time
|
||||
*/
|
||||
struct GNUNET_TIME_Absolute valid_until;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Mint's denomination key
|
||||
*/
|
||||
struct TALER_MINT_DenomPublicKey
|
||||
{
|
||||
/**
|
||||
* The public key
|
||||
*/
|
||||
struct TALER_RSA_PublicKeyBinaryEncoded key;
|
||||
|
||||
/**
|
||||
* Timestamp indicating when the denomination key becomes valid
|
||||
*/
|
||||
struct GNUNET_TIME_Absolute valid_from;
|
||||
|
||||
/**
|
||||
* Timestamp indicating when the denomination key can’t be used anymore to
|
||||
* withdraw new coins.
|
||||
*/
|
||||
struct GNUNET_TIME_Absolute withdraw_valid_until;
|
||||
|
||||
/**
|
||||
* Timestamp indicating when coins of this denomination become invalid.
|
||||
*/
|
||||
struct GNUNET_TIME_Absolute deposit_valid_until;
|
||||
|
||||
/**
|
||||
* The value of this denomination
|
||||
*/
|
||||
struct TALER_Amount value;
|
||||
|
||||
/**
|
||||
* The applicable fee for withdrawing a coin of this denomination
|
||||
*/
|
||||
struct TALER_Amount fee_withdraw;
|
||||
|
||||
/**
|
||||
* The applicable fee to spend a coin of this denomination
|
||||
*/
|
||||
struct TALER_Amount fee_deposit;
|
||||
|
||||
/**
|
||||
*The applicable fee to refresh a coin of this denomination
|
||||
*/
|
||||
struct TALER_Amount fee_refresh;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Initialise a context. A context should be used for each thread and should
|
||||
* not be shared among multiple threads.
|
||||
*
|
||||
* @return the context
|
||||
*/
|
||||
struct TALER_MINT_Context *
|
||||
TALER_MINT_init ();
|
||||
|
||||
|
||||
/**
|
||||
* Cleanup library initialisation resources. This function should be called
|
||||
* after using this library to cleanup the resources occupied during library's
|
||||
* initialisation.
|
||||
*
|
||||
* @param ctx the library context
|
||||
*/
|
||||
void
|
||||
TALER_MINT_cleanup (struct TALER_MINT_Context *ctx);
|
||||
|
||||
|
||||
/**
|
||||
* Initialise a connection to the mint.
|
||||
*
|
||||
* @param ctx the context
|
||||
* @param hostname the hostname of the mint
|
||||
* @param port the point where the mint's HTTP service is running. If port is
|
||||
* given as 0, ports 80 or 443 are chosen depending on @a url.
|
||||
* @param mint_key the public key of the mint. This is used to verify the
|
||||
* responses of the mint.
|
||||
* @return the mint handle; NULL upon error
|
||||
*/
|
||||
struct TALER_MINT_Handle *
|
||||
TALER_MINT_connect (struct TALER_MINT_Context *ctx,
|
||||
const char *hostname,
|
||||
uint16_t port,
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey *mint_key);
|
||||
|
||||
/**
|
||||
* Disconnect from the mint
|
||||
*
|
||||
* @param mint the mint handle
|
||||
*/
|
||||
void
|
||||
TALER_MINT_disconnect (struct TALER_MINT_Handle *mint);
|
||||
|
||||
|
||||
/**
|
||||
* A handle to get the keys of a mint
|
||||
*/
|
||||
struct TALER_MINT_KeysGetHandle;
|
||||
|
||||
/**
|
||||
* Functions of this type are called to signal completion of an asynchronous call.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param emsg if the asynchronous call could not be completed due to an error,
|
||||
* this parameter contains a human readable error message
|
||||
*/
|
||||
typedef void (*TALER_MINT_ContinuationCallback) (void *cls,
|
||||
const char *emsg);
|
||||
|
||||
/**
|
||||
* Functions of this type are called to provide the retrieved signing and
|
||||
* denomination keys of the mint. No TALER_MINT_*() functions should be called
|
||||
* in this callback.
|
||||
*
|
||||
* @param cls closure passed to TALER_MINT_keys_get()
|
||||
* @param sign_keys NULL-terminated array of pointers to the mint's signing
|
||||
* keys. NULL if no signing keys are retrieved.
|
||||
* @param denom_keys NULL-terminated array of pointers to the mint's
|
||||
* denomination keys; will be NULL if no signing keys are retrieved.
|
||||
*/
|
||||
typedef void (*TALER_MINT_KeysGetCallback) (void *cls,
|
||||
struct TALER_MINT_SigningPublicKey **sign_keys,
|
||||
struct TALER_MINT_DenomPublicKey **denom_keys);
|
||||
|
||||
|
||||
/**
|
||||
* Get the signing and denomination key of the mint.
|
||||
*
|
||||
* @param mint handle to the mint
|
||||
* @param cb the callback to call with the keys
|
||||
* @param cls closure for the above callback
|
||||
* @param cont_cb the callback to call after completing this asynchronous call
|
||||
* @param cont_cls the closure for the continuation callback
|
||||
* @return a handle to this asynchronous call; NULL upon eror
|
||||
*/
|
||||
struct TALER_MINT_KeysGetHandle *
|
||||
TALER_MINT_keys_get (struct TALER_MINT_Handle *mint,
|
||||
TALER_MINT_KeysGetCallback cb, void *cls,
|
||||
TALER_MINT_ContinuationCallback cont_cb, void *cont_cls);
|
||||
|
||||
/**
|
||||
* Cancel the asynchronous call initiated by TALER_MINT_keys_get(). This should
|
||||
* not be called if either of the @a TALER_MINT_KeysGetCallback or @a
|
||||
* TALER_MINT_ContinuationCallback passed to TALER_MINT_keys_get() have been
|
||||
* called.
|
||||
*
|
||||
* @param get the handle for retrieving the keys
|
||||
*/
|
||||
void
|
||||
TALER_MINT_keys_get_cancel (struct TALER_MINT_KeysGetHandle *get);
|
||||
|
||||
|
||||
/**
|
||||
* A Deposit Handle
|
||||
*/
|
||||
struct TALER_MINT_DepositHandle;
|
||||
|
||||
|
||||
/**
|
||||
* Callbacks of this type are used to serve the result of submitting a deposit
|
||||
* permission object to a mint
|
||||
*
|
||||
* @param cls closure
|
||||
* @param status 1 for successful deposit, 2 for retry, 0 for failure
|
||||
* @param obj the received JSON object; can be NULL if it cannot be constructed
|
||||
* from the reply
|
||||
* @param emsg in case of unsuccessful deposit, this contains a human readable
|
||||
* explanation.
|
||||
*/
|
||||
typedef void (*TALER_MINT_DepositResultCallback) (void *cls,
|
||||
int status,
|
||||
json_t *obj,
|
||||
char *emsg);
|
||||
|
||||
/**
|
||||
* Submit a deposit permission to the mint and get the mint's response
|
||||
*
|
||||
* @param mint the mint handle
|
||||
* @param cb the callback to call when a reply for this request is available
|
||||
* @param cls closure for the above callback
|
||||
* @param deposit_obj the deposit permission received from the customer along
|
||||
* with the wireformat JSON object
|
||||
* @return a handle for this request; NULL if the JSON object could not be
|
||||
* parsed or is of incorrect format or any other error. In this case,
|
||||
* the callback is not called.
|
||||
*/
|
||||
struct TALER_MINT_DepositHandle *
|
||||
TALER_MINT_deposit_submit_json (struct TALER_MINT_Handle *mint,
|
||||
TALER_MINT_DepositResultCallback cb,
|
||||
void *cls,
|
||||
json_t *deposit_obj);
|
||||
|
||||
|
||||
#if 0
|
||||
/**
|
||||
* Submit a deposit permission to the mint and get the mint's response.
|
||||
*
|
||||
* @param mint the mint handle
|
||||
* @param cb the callback to call when a reply for this request is available
|
||||
* @param cls closure for the above callback
|
||||
* @param coin the public key of the coin
|
||||
* @param denom_key denomination key of the mint which is used to blind-sign the
|
||||
* coin
|
||||
* @param ubsig the mint's unblinded signature
|
||||
* @param transaction_id transaction identifier
|
||||
* @param amount the amount to deposit
|
||||
* @param merchant_pub the public key of the merchant
|
||||
* @param h_contract hash of the contract
|
||||
* @param h_wire hash of the wire format used
|
||||
* @param csig signature of the coin over the transaction_id, amount,
|
||||
* merchant_pub, h_contract and, h_wire
|
||||
* @param wire_obj the wireformat object corresponding to h_wire
|
||||
* @return a handle for this request
|
||||
*/
|
||||
struct TALER_MINT_DepositHandle *
|
||||
TALER_MINT_deposit_submit_json_ (struct TALER_MINT_Handle *mint,
|
||||
TALER_MINT_DepositResultCallback *cb,
|
||||
void *cls,
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey *coin_pub,
|
||||
struct TALER_BLIND_SigningPublicKey *denom_pub,
|
||||
struct TALER_BLIND_Signature *ubsig,
|
||||
uint64_t transaction_id,
|
||||
struct TALER_Amount *amount,
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey *merchant_pub,
|
||||
struct GNUNET_HashCode *h_contract,
|
||||
struct GNUNET_HashCode *h_wire,
|
||||
struct GNUNET_CRYPTO_EddsaSignature *csig,
|
||||
json_t *wire_obj);
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Cancel a deposit permission request. This function cannot be used on a
|
||||
* request handle if a response is already served for it.
|
||||
*
|
||||
* @param the deposit permission request handle
|
||||
*/
|
||||
void
|
||||
TALER_MINT_deposit_submit_cancel (struct TALER_MINT_DepositHandle *deposit);
|
||||
|
||||
#endif /* _TALER_MINT_SERVICE_H */
|
357
src/include/taler_rsa.h
Normal file
357
src/include/taler_rsa.h
Normal file
@ -0,0 +1,357 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file include/taler_rsa.h
|
||||
* @brief RSA key management utilities. Some code is taken from gnunet-0.9.5a
|
||||
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||
*
|
||||
* Authors of the gnunet code:
|
||||
* Christian Grothoff
|
||||
* Krista Bennett
|
||||
* Gerd Knorr <kraxel@bytesex.org>
|
||||
* Ioana Patrascu
|
||||
* Tzvetan Horozov
|
||||
*/
|
||||
|
||||
#ifndef TALER_RSA_H
|
||||
#define TALER_RSA_H
|
||||
|
||||
#include <gnunet/gnunet_common.h>
|
||||
#include <gnunet/gnunet_crypto_lib.h>
|
||||
|
||||
/**
|
||||
* Length of an RSA KEY (n,e,len), 2048 bit (=256 octests) key n, 2 byte e
|
||||
*/
|
||||
#define TALER_RSA_KEY_LENGTH 258
|
||||
|
||||
/**
|
||||
* @brief Length of RSA encrypted data (2048 bit)
|
||||
*
|
||||
* We currently do not handle encryption of data
|
||||
* that can not be done in a single call to the
|
||||
* RSA methods (read: large chunks of data).
|
||||
* We should never need that, as we can use
|
||||
* the GNUNET_CRYPTO_hash for larger pieces of data for signing,
|
||||
* and for encryption, we only need to encode sessionkeys!
|
||||
*/
|
||||
#define TALER_RSA_DATA_ENCODING_LENGTH 256
|
||||
|
||||
/**
|
||||
* The private information of an RSA key pair.
|
||||
*/
|
||||
struct TALER_RSA_PrivateKey;
|
||||
|
||||
|
||||
GNUNET_NETWORK_STRUCT_BEGIN
|
||||
|
||||
/**
|
||||
* GNUnet mandates a certain format for the encoding
|
||||
* of private RSA key information that is provided
|
||||
* by the RSA implementations. This format is used
|
||||
* to serialize a private RSA key (typically when
|
||||
* writing it to disk).
|
||||
*/
|
||||
struct TALER_RSA_PrivateKeyBinaryEncoded
|
||||
{
|
||||
/**
|
||||
* Total size of the structure, in bytes, in big-endian!
|
||||
*/
|
||||
uint16_t len GNUNET_PACKED;
|
||||
uint16_t sizen GNUNET_PACKED; /* in big-endian! */
|
||||
uint16_t sizee GNUNET_PACKED; /* in big-endian! */
|
||||
uint16_t sized GNUNET_PACKED; /* in big-endian! */
|
||||
uint16_t sizep GNUNET_PACKED; /* in big-endian! */
|
||||
uint16_t sizeq GNUNET_PACKED; /* in big-endian! */
|
||||
uint16_t sizedmp1 GNUNET_PACKED; /* in big-endian! */
|
||||
uint16_t sizedmq1 GNUNET_PACKED; /* in big-endian! */
|
||||
/* followed by the actual values */
|
||||
};
|
||||
GNUNET_NETWORK_STRUCT_END
|
||||
|
||||
|
||||
/**
|
||||
* @brief an RSA signature
|
||||
*/
|
||||
struct TALER_RSA_Signature
|
||||
{
|
||||
unsigned char sig[TALER_RSA_DATA_ENCODING_LENGTH];
|
||||
};
|
||||
|
||||
GNUNET_NETWORK_STRUCT_BEGIN
|
||||
/**
|
||||
* @brief header of what an RSA signature signs
|
||||
* this must be followed by "size - 8" bytes of
|
||||
* the actual signed data
|
||||
*/
|
||||
struct TALER_RSA_SignaturePurpose
|
||||
{
|
||||
/**
|
||||
* How many bytes does this signature sign?
|
||||
* (including this purpose header); in network
|
||||
* byte order (!).
|
||||
*/
|
||||
uint32_t size GNUNET_PACKED;
|
||||
|
||||
/**
|
||||
* What does this signature vouch for? This
|
||||
* must contain a GNUNET_SIGNATURE_PURPOSE_XXX
|
||||
* constant (from gnunet_signatures.h). In
|
||||
* network byte order!
|
||||
*/
|
||||
uint32_t purpose GNUNET_PACKED;
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct TALER_RSA_BlindedSignaturePurpose
|
||||
{
|
||||
unsigned char data[TALER_RSA_DATA_ENCODING_LENGTH];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief A public key.
|
||||
*/
|
||||
struct TALER_RSA_PublicKeyBinaryEncoded
|
||||
{
|
||||
/**
|
||||
* In big-endian, must be GNUNET_CRYPTO_RSA_KEY_LENGTH+4
|
||||
*/
|
||||
uint16_t len GNUNET_PACKED;
|
||||
|
||||
/**
|
||||
* Size of n in key; in big-endian!
|
||||
*/
|
||||
uint16_t sizen GNUNET_PACKED;
|
||||
|
||||
/**
|
||||
* The key itself, contains n followed by e.
|
||||
*/
|
||||
unsigned char key[TALER_RSA_KEY_LENGTH];
|
||||
|
||||
/**
|
||||
* Padding (must be 0)
|
||||
*/
|
||||
uint16_t padding GNUNET_PACKED;
|
||||
};
|
||||
|
||||
GNUNET_NETWORK_STRUCT_END
|
||||
|
||||
/**
|
||||
* Create a new private key. Caller must free return value.
|
||||
*
|
||||
* @return fresh private key
|
||||
*/
|
||||
struct TALER_RSA_PrivateKey *
|
||||
TALER_RSA_key_create ();
|
||||
|
||||
|
||||
/**
|
||||
* Free memory occupied by the private key.
|
||||
*
|
||||
* @param key pointer to the memory to free
|
||||
*/
|
||||
void
|
||||
TALER_RSA_key_free (struct TALER_RSA_PrivateKey *key);
|
||||
|
||||
|
||||
/**
|
||||
* Encode the private key in a format suitable for
|
||||
* storing it into a file.
|
||||
* @return encoding of the private key
|
||||
*/
|
||||
struct TALER_RSA_PrivateKeyBinaryEncoded *
|
||||
TALER_RSA_encode_key (const struct TALER_RSA_PrivateKey *hostkey);
|
||||
|
||||
|
||||
/**
|
||||
* Extract the public key of the given private key.
|
||||
*
|
||||
* @param priv the private key
|
||||
* @param pub where to write the public key
|
||||
*/
|
||||
void
|
||||
TALER_RSA_key_get_public (const struct TALER_RSA_PrivateKey *priv,
|
||||
struct TALER_RSA_PublicKeyBinaryEncoded *pub);
|
||||
|
||||
|
||||
/**
|
||||
* Decode the private key from the data-format back
|
||||
* to the "normal", internal format.
|
||||
*
|
||||
* @param buf the buffer where the private key data is stored
|
||||
* @param len the length of the data in 'buffer'
|
||||
* @return NULL on error
|
||||
*/
|
||||
struct TALER_RSA_PrivateKey *
|
||||
TALER_RSA_decode_key (const char *buf, uint16_t len);
|
||||
|
||||
|
||||
/**
|
||||
* Convert a public key to a string.
|
||||
*
|
||||
* @param pub key to convert
|
||||
* @return string representing 'pub'
|
||||
*/
|
||||
char *
|
||||
TALER_RSA_public_key_to_string (const struct TALER_RSA_PublicKeyBinaryEncoded *pub);
|
||||
|
||||
|
||||
/**
|
||||
* Convert a string representing a public key to a public key.
|
||||
*
|
||||
* @param enc encoded public key
|
||||
* @param enclen number of bytes in enc (without 0-terminator)
|
||||
* @param pub where to store the public key
|
||||
* @return GNUNET_OK on success
|
||||
*/
|
||||
int
|
||||
TALER_RSA_public_key_from_string (const char *enc,
|
||||
size_t enclen,
|
||||
struct TALER_RSA_PublicKeyBinaryEncoded *pub);
|
||||
|
||||
|
||||
/**
|
||||
* Sign a given block.h
|
||||
*
|
||||
* @param key private key to use for the signing
|
||||
* @param msg the message
|
||||
* @param size the size of the message
|
||||
* @param sig where to write the signature
|
||||
* @return GNUNET_SYSERR on error, GNUNET_OK on success
|
||||
*/
|
||||
int
|
||||
TALER_RSA_sign (const struct TALER_RSA_PrivateKey *key,
|
||||
const void *msg,
|
||||
size_t size,
|
||||
struct TALER_RSA_Signature *sig);
|
||||
|
||||
|
||||
/**
|
||||
* Verify signature with the given hash.
|
||||
*
|
||||
* @param hash the hash code to verify against the signature
|
||||
* @param sig signature that is being validated
|
||||
* @param publicKey public key of the signer
|
||||
* @returns GNUNET_OK if ok, GNUNET_SYSERR if invalid
|
||||
*/
|
||||
int
|
||||
TALER_RSA_hash_verify (const struct GNUNET_HashCode *hash,
|
||||
const struct TALER_RSA_Signature *sig,
|
||||
const struct TALER_RSA_PublicKeyBinaryEncoded *publicKey);
|
||||
|
||||
|
||||
/**
|
||||
* Verify signature on the given message
|
||||
*
|
||||
* @param msg the message
|
||||
* @param size the size of the message
|
||||
* @param sig signature that is being validated
|
||||
* @param publicKey public key of the signer
|
||||
* @returns GNUNET_OK if ok, GNUNET_SYSERR if invalid
|
||||
*/
|
||||
int
|
||||
TALER_RSA_verify (const void *msg, size_t size,
|
||||
const struct TALER_RSA_Signature *sig,
|
||||
const struct TALER_RSA_PublicKeyBinaryEncoded *publicKey);
|
||||
|
||||
/**
|
||||
* Key used to blind a message
|
||||
*/
|
||||
struct TALER_RSA_BlindingKey;
|
||||
|
||||
/**
|
||||
* Create a blinding key
|
||||
*
|
||||
* @return the newly created blinding key
|
||||
*/
|
||||
struct TALER_RSA_BlindingKey *
|
||||
TALER_RSA_blinding_key_create ();
|
||||
|
||||
|
||||
/**
|
||||
* Destroy a blinding key
|
||||
*
|
||||
* @param bkey the blinding key to destroy
|
||||
*/
|
||||
void
|
||||
TALER_RSA_blinding_key_destroy (struct TALER_RSA_BlindingKey *bkey);
|
||||
|
||||
|
||||
/**
|
||||
* Binary encoding for TALER_RSA_BlindingKey
|
||||
*/
|
||||
struct TALER_RSA_BlindingKeyBinaryEncoded
|
||||
{
|
||||
unsigned char data[TALER_RSA_DATA_ENCODING_LENGTH];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Encode a blinding key
|
||||
*
|
||||
* @param bkey the blinding key to encode
|
||||
* @param bkey_enc where to store the encoded binary key
|
||||
* @return #GNUNET_OK upon successful encoding; #GNUNET_SYSERR upon failure
|
||||
*/
|
||||
int
|
||||
TALER_RSA_blinding_key_encode (struct TALER_RSA_BlindingKey *bkey,
|
||||
struct TALER_RSA_BlindingKeyBinaryEncoded *bkey_enc);
|
||||
|
||||
|
||||
/**
|
||||
* Decode a blinding key from its encoded form
|
||||
*
|
||||
* @param bkey_enc the encoded blinding key
|
||||
* @return the decoded blinding key; NULL upon error
|
||||
*/
|
||||
struct TALER_RSA_BlindingKey *
|
||||
TALER_RSA_blinding_key_decode (struct TALER_RSA_BlindingKeyBinaryEncoded *bkey_enc);
|
||||
|
||||
|
||||
/**
|
||||
* Blinds the given message with the given blinding key
|
||||
*
|
||||
* @param msg the message
|
||||
* @param size the size of the message
|
||||
* @param bkey the blinding key
|
||||
* @param pkey the public key of the signer
|
||||
* @return the blinding signature purpose; NULL upon any error
|
||||
*/
|
||||
struct TALER_RSA_BlindedSignaturePurpose *
|
||||
TALER_RSA_message_blind (const void *msg, size_t size,
|
||||
struct TALER_RSA_BlindingKey *bkey,
|
||||
struct TALER_RSA_PublicKeyBinaryEncoded *pkey);
|
||||
|
||||
|
||||
/**
|
||||
* Unblind a signature made on blinding signature purpose. The signature
|
||||
* purpose should have been generated with TALER_RSA_message_blind() function.
|
||||
*
|
||||
* @param sig the signature made on the blinded signature purpose
|
||||
* @param bkey the blinding key used to blind the signature purpose
|
||||
* @param pkey the public key of the signer
|
||||
* @return GNUNET_SYSERR upon error; GNUNET_OK upon success.
|
||||
*/
|
||||
int
|
||||
TALER_RSA_unblind (struct TALER_RSA_Signature *sig,
|
||||
struct TALER_RSA_BlindingKey *bkey,
|
||||
struct TALER_RSA_PublicKeyBinaryEncoded *pkey);
|
||||
|
||||
#endif /* TALER_RSA_H */
|
||||
|
||||
/* end of include/taler_rsa.h */
|
106
src/include/taler_signatures.h
Normal file
106
src/include/taler_signatures.h
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file taler-mint-keyup.c
|
||||
* @brief Update the mint's keys for coins and signatures,
|
||||
* using the mint's offline master key.
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
*/
|
||||
|
||||
#ifndef TALER_SIGNATURES_H
|
||||
#define TALER_SIGNATURES_H
|
||||
|
||||
/**
|
||||
* Purpose for signing public keys signed
|
||||
* by the mint master key.
|
||||
*/
|
||||
#define TALER_SIGNATURE_MASTER_SIGNKEY 1
|
||||
|
||||
/**
|
||||
* Purpose for denomination keys signed
|
||||
* by the mint master key.
|
||||
*/
|
||||
#define TALER_SIGNATURE_MASTER_DENOM 2
|
||||
|
||||
/**
|
||||
* Purpose for the state of a reserve,
|
||||
* signed by the mint's signing key.
|
||||
*/
|
||||
#define TALER_SIGNATURE_RESERVE_STATUS 3
|
||||
|
||||
/**
|
||||
* Signature where the reserve key
|
||||
* confirms a withdraw request.
|
||||
*/
|
||||
#define TALER_SIGNATURE_WITHDRAW 4
|
||||
|
||||
/**
|
||||
* Signature where the refresh session confirms
|
||||
* the list of melted coins and requested denominations.
|
||||
*/
|
||||
#define TALER_SIGNATURE_REFRESH_MELT 5
|
||||
|
||||
/**
|
||||
* Signature where the refresh session confirms
|
||||
* the commits.
|
||||
*/
|
||||
#define TALER_SIGNATURE_REFRESH_COMMIT 6
|
||||
|
||||
/**
|
||||
* Signature where the mint (current signing key)
|
||||
* confirms the list of blind session keys.
|
||||
*/
|
||||
#define TALER_SIGNATURE_REFRESH_MELT_RESPONSE 7
|
||||
|
||||
/**
|
||||
* Signature where the mint (current signing key)
|
||||
* confirms the no-reveal index for cut-and-choose.
|
||||
*/
|
||||
#define TALER_SIGNATURE_REFRESH_COMMIT_RESPONSE 8
|
||||
|
||||
/**
|
||||
* Signature where coins confirm that they want
|
||||
* to be melted into a certain session.
|
||||
*/
|
||||
#define TALER_SIGNATURE_REFRESH_MELT_CONFIRM 9
|
||||
|
||||
/***********************/
|
||||
/* Merchant signatures */
|
||||
/***********************/
|
||||
|
||||
/**
|
||||
* Signature where the merchant confirms a contract
|
||||
*/
|
||||
#define TALER_SIGNATURE_MERCHANT_CONTRACT 101
|
||||
|
||||
/*********************/
|
||||
/* Wallet signatures */
|
||||
/*********************/
|
||||
|
||||
/**
|
||||
* Signature made by the wallet of a user to confirm a deposit permission
|
||||
*/
|
||||
#define TALER_SIGNATURE_DEPOSIT 201
|
||||
|
||||
/**
|
||||
* Signature made by the wallet of a user to confirm a incremental deposit permission
|
||||
*/
|
||||
#define TALER_SIGNATURE_INCREMENTAL_DEPOSIT 202
|
||||
|
||||
#endif
|
||||
|
120
src/include/taler_types.h
Normal file
120
src/include/taler_types.h
Normal file
@ -0,0 +1,120 @@
|
||||
/**
|
||||
* @file include/types.h
|
||||
* @brief This files defines the various data and message types in TALER.
|
||||
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||
* @author Florian Dold
|
||||
*/
|
||||
|
||||
#ifndef TYPES_H_
|
||||
#define TYPES_H_
|
||||
|
||||
#include "taler_rsa.h"
|
||||
|
||||
|
||||
/**
|
||||
* Public information about a coin.
|
||||
*/
|
||||
struct TALER_CoinPublicInfo
|
||||
{
|
||||
/**
|
||||
* The coin's public key.
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EcdsaPublicKey coin_pub;
|
||||
|
||||
/*
|
||||
* The public key signifying the coin's denomination.
|
||||
*/
|
||||
struct TALER_RSA_PublicKeyBinaryEncoded denom_pub;
|
||||
|
||||
/**
|
||||
* Signature over coin_pub by denom_pub.
|
||||
*/
|
||||
struct TALER_RSA_Signature denom_sig;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Request to withdraw coins from a reserve.
|
||||
*/
|
||||
struct TALER_WithdrawRequest
|
||||
{
|
||||
/**
|
||||
* Signature over the rest of the message
|
||||
* by the withdraw public key.
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EddsaSignature sig;
|
||||
|
||||
/**
|
||||
* Purpose must be TALER_SIGNATURE_WITHDRAW.
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||
|
||||
/**
|
||||
* Reserve public key.
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
|
||||
|
||||
/**
|
||||
* Denomination public key for the coin that is withdrawn.
|
||||
*/
|
||||
struct TALER_RSA_PublicKeyBinaryEncoded denomination_pub;
|
||||
|
||||
/**
|
||||
* Purpose containing coin's blinded public key.
|
||||
*/
|
||||
struct TALER_RSA_BlindedSignaturePurpose coin_envelope;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Data type for messages
|
||||
*/
|
||||
struct TALER_MessageHeader
|
||||
{
|
||||
/**
|
||||
* The type of the message in Network-byte order (NBO)
|
||||
*/
|
||||
uint16_t type;
|
||||
|
||||
/**
|
||||
* The size of the message in NBO
|
||||
*/
|
||||
uint16_t size;
|
||||
};
|
||||
|
||||
/*****************/
|
||||
/* Message types */
|
||||
/*****************/
|
||||
|
||||
/**
|
||||
* The message type of a blind signature
|
||||
*/
|
||||
#define TALER_MSG_TYPE_BLINDED_SIGNATURE 1
|
||||
|
||||
/**
|
||||
* The message type of a blinded message
|
||||
*/
|
||||
#define TALER_MSG_TYPE_BLINDED_MESSAGE 2
|
||||
|
||||
/**
|
||||
* The message type of an unblinded signature
|
||||
* @FIXME: Not currently used
|
||||
*/
|
||||
#define TALER_MSG_TYPE_UNBLINDED_SIGNATURE 3
|
||||
|
||||
/**
|
||||
* The type of a blinding residue message
|
||||
* @FIXME: Not currently used
|
||||
*/
|
||||
#define TALER_MSG_TYPE_BLINDING_RESIDUE 4
|
||||
|
||||
/**
|
||||
* The type of a message containing the blinding factor
|
||||
*/
|
||||
#define TALER_MSG_TYPE_BLINDING_FACTOR 5
|
||||
|
||||
|
||||
#endif /* TYPES_H_ */
|
||||
|
||||
/* end of include/types.h */
|
255
src/include/taler_util.h
Normal file
255
src/include/taler_util.h
Normal file
@ -0,0 +1,255 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file include/taler_util.h
|
||||
* @brief Interface for common utility functions
|
||||
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||
*/
|
||||
|
||||
#ifndef UTIL_H_
|
||||
#define UTIL_H_
|
||||
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <gcrypt.h>
|
||||
|
||||
/* Define logging functions */
|
||||
#define LOG_DEBUG(...) \
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__)
|
||||
|
||||
#define LOG_WARNING(...) \
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, __VA_ARGS__)
|
||||
|
||||
#define LOG_ERROR(...) \
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, __VA_ARGS__)
|
||||
|
||||
|
||||
/**
|
||||
* Tests a given as assertion and if failed prints it as a warning with the
|
||||
* given reason
|
||||
*
|
||||
* @param EXP the expression to test as assertion
|
||||
* @param reason string to print as warning
|
||||
*/
|
||||
#define TALER_assert_as(EXP, reason) \
|
||||
do { \
|
||||
if (EXP) break; \
|
||||
LOG_ERROR("%s at %s:%d\n", reason, __FILE__, __LINE__); \
|
||||
abort(); \
|
||||
} while(0)
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Log an error message at log-level 'level' that indicates
|
||||
* a failure of the command 'cmd' with the message given
|
||||
* by gcry_strerror(rc).
|
||||
*/
|
||||
#define LOG_GCRY_ERROR(cmd, rc) do { LOG_ERROR("`%s' failed at %s:%d with error: %s\n", cmd, __FILE__, __LINE__, gcry_strerror(rc)); } while(0)
|
||||
|
||||
|
||||
#define TALER_gcry_ok(cmd) \
|
||||
do {int rc; rc = cmd; if (!rc) break; LOG_ERROR("A Gcrypt call failed at %s:%d with error: %s\n", __FILE__, __LINE__, gcry_strerror(rc)); abort(); } while (0)
|
||||
|
||||
|
||||
#define TALER_CURRENCY_LEN 4
|
||||
|
||||
|
||||
GNUNET_NETWORK_STRUCT_BEGIN
|
||||
|
||||
struct TALER_AmountNBO
|
||||
{
|
||||
uint32_t value;
|
||||
uint32_t fraction;
|
||||
char currency[TALER_CURRENCY_LEN];
|
||||
};
|
||||
|
||||
GNUNET_NETWORK_STRUCT_END
|
||||
|
||||
struct TALER_HashContext
|
||||
{
|
||||
gcry_md_hd_t hd;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Representation of monetary value in a given currency.
|
||||
*/
|
||||
struct TALER_Amount
|
||||
{
|
||||
/**
|
||||
* Value (numerator of fraction)
|
||||
*/
|
||||
uint32_t value;
|
||||
/**
|
||||
* Fraction (denominator of fraction)
|
||||
*/
|
||||
uint32_t fraction;
|
||||
/**
|
||||
* Currency string, left adjusted and padded with zeros.
|
||||
*/
|
||||
char currency[4];
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Initialize Gcrypt library.
|
||||
*/
|
||||
void
|
||||
TALER_gcrypt_init();
|
||||
|
||||
|
||||
/**
|
||||
* Generate a ECC private key.
|
||||
*
|
||||
* @return the s-expression representing the generated ECC private key; NULL
|
||||
* upon error
|
||||
*/
|
||||
gcry_sexp_t
|
||||
TALER_genkey ();
|
||||
|
||||
|
||||
/**
|
||||
* Parse denomination description, in the format "T : V : F".
|
||||
*
|
||||
* @param str denomination description
|
||||
* @param denom denomination to write the result to
|
||||
* @return GNUNET_OK if the string is a valid denomination specification,
|
||||
* GNUNET_SYSERR if it is invalid.
|
||||
*/
|
||||
int
|
||||
TALER_string_to_amount (const char *str, struct TALER_Amount *denom);
|
||||
|
||||
|
||||
/**
|
||||
* FIXME
|
||||
*/
|
||||
struct TALER_AmountNBO
|
||||
TALER_amount_hton (struct TALER_Amount d);
|
||||
|
||||
|
||||
/**
|
||||
* FIXME
|
||||
*/
|
||||
struct TALER_Amount
|
||||
TALER_amount_ntoh (struct TALER_AmountNBO dn);
|
||||
|
||||
/**
|
||||
* Compare the value/fraction of two amounts. Does not compare the currency,
|
||||
* i.e. comparing amounts with the same value and fraction but different
|
||||
* currency would return 0.
|
||||
*
|
||||
* @param a1 first amount
|
||||
* @param a2 second amount
|
||||
* @return result of the comparison
|
||||
*/
|
||||
int
|
||||
TALER_amount_cmp (struct TALER_Amount a1, struct TALER_Amount a2);
|
||||
|
||||
|
||||
/**
|
||||
* Perform saturating subtraction of amounts.
|
||||
*
|
||||
* @param a1 amount to subtract from
|
||||
* @param a2 amount to subtract
|
||||
* @return (a1-a2) or 0 if a2>=a1
|
||||
*/
|
||||
struct TALER_Amount
|
||||
TALER_amount_subtract (struct TALER_Amount a1, struct TALER_Amount a2);
|
||||
|
||||
|
||||
/**
|
||||
* Perform saturating addition of amounts
|
||||
*
|
||||
* @param a1 first amount to add
|
||||
* @param a2 second amount to add
|
||||
* @return sum of a1 and a2
|
||||
*/
|
||||
struct TALER_Amount
|
||||
TALER_amount_add (struct TALER_Amount a1, struct TALER_Amount a2);
|
||||
|
||||
|
||||
/**
|
||||
* Normalize the given amount.
|
||||
*
|
||||
* @param amout amount to normalize
|
||||
* @return normalized amount
|
||||
*/
|
||||
struct TALER_Amount
|
||||
TALER_amount_normalize (struct TALER_Amount amount);
|
||||
|
||||
|
||||
/**
|
||||
* Convert amount to string.
|
||||
*
|
||||
* @param amount amount to convert to string
|
||||
* @return freshly allocated string representation
|
||||
*/
|
||||
char *
|
||||
TALER_amount_to_string (struct TALER_Amount amount);
|
||||
|
||||
|
||||
/**
|
||||
* Return the base32crockford encoding of the given buffer.
|
||||
*
|
||||
* The returned string will be freshly allocated, and must be free'd
|
||||
* with GNUNET_free.
|
||||
*
|
||||
* @param buffer with data
|
||||
* @param size size of the buffer
|
||||
* @return freshly allocated, null-terminated string
|
||||
*/
|
||||
char *
|
||||
TALER_data_to_string_alloc (const void *buf, size_t size);
|
||||
|
||||
|
||||
/**
|
||||
* Get encoded binary data from a configuration.
|
||||
*
|
||||
* @return GNUNET_OK on success
|
||||
* GNUNET_NO is the value does not exist
|
||||
* GNUNET_SYSERR on encoding error
|
||||
*/
|
||||
int
|
||||
TALER_configuration_get_data (const struct GNUNET_CONFIGURATION_Handle *cfg,
|
||||
const char *section, const char *option,
|
||||
void *buf, size_t buf_size);
|
||||
|
||||
|
||||
|
||||
|
||||
int
|
||||
TALER_refresh_decrypt (const void *input, size_t input_size, const struct GNUNET_HashCode *secret, void *result);
|
||||
|
||||
int
|
||||
TALER_refresh_encrypt (const void *input, size_t input_size, const struct GNUNET_HashCode *secret, void *result);
|
||||
|
||||
|
||||
|
||||
void
|
||||
TALER_hash_context_start (struct TALER_HashContext *hc);
|
||||
|
||||
|
||||
void
|
||||
TALER_hash_context_read (struct TALER_HashContext *hc, void *buf, size_t size);
|
||||
|
||||
|
||||
void
|
||||
TALER_hash_context_finish (struct TALER_HashContext *hc,
|
||||
struct GNUNET_HashCode *r_hash);
|
||||
|
||||
#endif
|
6
src/mint/.gitignore
vendored
Normal file
6
src/mint/.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
taler-mint-dbinit
|
||||
taler-mint-keycheck
|
||||
taler-mint-keyup
|
||||
taler-mint-pursemod
|
||||
taler-mint-reservemod
|
||||
taler-mint-httpd
|
131
src/mint/Makefile.am
Normal file
131
src/mint/Makefile.am
Normal file
@ -0,0 +1,131 @@
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src/include $(POSTGRESQL_CPPFLAGS)
|
||||
|
||||
lib_LTLIBRARIES = \
|
||||
libtalermint.la \
|
||||
libtalermintapi.la
|
||||
|
||||
libtalermint_la_SOURCES = \
|
||||
mint_common.c \
|
||||
mint_db.c
|
||||
|
||||
libtalermint_la_LIBADD = \
|
||||
$(top_builddir)/src/util/libtalerutil.la \
|
||||
-lgnunetutil \
|
||||
-lpq
|
||||
|
||||
libtalermint_la_LDFLAGS = \
|
||||
$(POSTGRESQL_LDFLAGS) \
|
||||
-version-info 0:0:0 \
|
||||
-no-undefined
|
||||
|
||||
libtalermintapi_la_SOURCES = \
|
||||
mint_api.c
|
||||
|
||||
libtalermintapi_la_LIBADD = \
|
||||
-lgnunetutil \
|
||||
-ljansson \
|
||||
-lcurl
|
||||
|
||||
libtalermintapi_la_LDFLAGS = \
|
||||
-version-info 0:0:0 \
|
||||
-no-undefined
|
||||
|
||||
|
||||
bin_PROGRAMS = \
|
||||
taler-mint-keyup \
|
||||
taler-mint-keycheck \
|
||||
taler-mint-reservemod \
|
||||
taler-mint-httpd \
|
||||
taler-mint-dbinit
|
||||
|
||||
taler_mint_keyup_SOURCES = \
|
||||
taler-mint-keyup.c
|
||||
|
||||
taler_mint_keyup_LDADD = \
|
||||
$(LIBGCRYPT_LIBS) \
|
||||
$(top_builddir)/src/util/libtalerutil.la \
|
||||
$(top_builddir)/src/mint/libtalermint.la \
|
||||
-lpq \
|
||||
-lgnunetutil
|
||||
taler_mint_keyup_LDFLAGS = $(POSTGRESQL_LDFLAGS)
|
||||
|
||||
|
||||
taler_mint_keycheck_SOURCES = \
|
||||
taler-mint-keycheck.c
|
||||
|
||||
taler_mint_keycheck_LDADD = \
|
||||
$(LIBGCRYPT_LIBS) \
|
||||
$(top_builddir)/src/util/libtalerutil.la \
|
||||
$(top_builddir)/src/mint/libtalermint.la \
|
||||
-lgnunetutil \
|
||||
-lpq
|
||||
taler_mint_keycheck_LDFLAGS = $(POSTGRESQL_LDFLAGS)
|
||||
|
||||
taler_mint_reservemod_SOURCES = \
|
||||
taler-mint-reservemod.c
|
||||
taler_mint_reservemod_LDADD = \
|
||||
$(LIBGCRYPT_LIBS) \
|
||||
$(top_builddir)/src/util/libtalerutil.la \
|
||||
$(top_builddir)/src/mint/libtalermint.la \
|
||||
-lpq \
|
||||
-lgnunetutil
|
||||
taler_mint_reservemod_LDFLAGS = \
|
||||
$(POSTGRESQL_LDFLAGS)
|
||||
|
||||
taler_mint_httpd_SOURCES = \
|
||||
taler-mint-httpd.c \
|
||||
taler-mint-httpd_mhd.c \
|
||||
taler-mint-httpd_keys.c \
|
||||
taler-mint-httpd_deposit.c \
|
||||
taler-mint-httpd_withdraw.c \
|
||||
taler-mint-httpd_refresh.c
|
||||
taler_mint_httpd_LDADD = \
|
||||
$(LIBGCRYPT_LIBS) \
|
||||
$(top_builddir)/src/util/libtalerutil.la \
|
||||
$(top_builddir)/src/mint/libtalermint.la \
|
||||
-lpq \
|
||||
-lmicrohttpd \
|
||||
-ljansson \
|
||||
-lgnunetutil \
|
||||
-lpthread
|
||||
taler_mint_httpd_LDFLAGS = \
|
||||
$(POSTGRESQL_LDFLAGS)
|
||||
|
||||
|
||||
taler_mint_dbinit_SOURCES = \
|
||||
taler-mint-dbinit.c
|
||||
taler_mint_dbinit_LDADD = \
|
||||
$(LIBGCRYPT_LIBS) \
|
||||
$(top_builddir)/src/util/libtalerutil.la \
|
||||
$(top_builddir)/src/mint/libtalermint.la \
|
||||
-lpq \
|
||||
-lgnunetutil
|
||||
taler_mint_dbinit_LDFLAGS = $(POSTGRESQL_LDFLAGS)
|
||||
|
||||
check_PROGRAMS = \
|
||||
test-mint-api \
|
||||
test-mint-deposits \
|
||||
test-mint-common
|
||||
|
||||
test_mint_api_SOURCES = test_mint_api.c
|
||||
test_mint_api_LDADD = \
|
||||
libtalermintapi.la \
|
||||
$(LIBGCRYPT_LIBS) \
|
||||
$(top_builddir)/src/util/libtalerutil.la \
|
||||
-lgnunetutil \
|
||||
-ljansson
|
||||
|
||||
test_mint_deposits_SOURCES = \
|
||||
test_mint_deposits.c
|
||||
test_mint_deposits_LDADD = \
|
||||
libtalermint.la \
|
||||
$(top_srcdir)/src/util/libtalerutil.la \
|
||||
-lgnunetutil \
|
||||
-lpq
|
||||
|
||||
test_mint_common_SOURCES = \
|
||||
test_mint_common.c
|
||||
test_mint_common_LDADD = \
|
||||
libtalermint.la \
|
||||
$(top_srcdir)/src/util/libtalerutil.la \
|
||||
-lgnunetutil
|
198
src/mint/mint.h
Normal file
198
src/mint/mint.h
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file taler_mint.h
|
||||
* @brief Common functionality for the mint
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
*/
|
||||
|
||||
#ifndef _MINT_H
|
||||
#define _MINT_H
|
||||
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <gnunet/gnunet_common.h>
|
||||
#include <libpq-fe.h>
|
||||
#include "taler_util.h"
|
||||
#include "taler_rsa.h"
|
||||
|
||||
#define DIR_SIGNKEYS "signkeys"
|
||||
#define DIR_DENOMKEYS "denomkeys"
|
||||
|
||||
|
||||
GNUNET_NETWORK_STRUCT_BEGIN
|
||||
|
||||
|
||||
/**
|
||||
* FIXME
|
||||
*/
|
||||
struct TALER_MINT_SignKeyIssue
|
||||
{
|
||||
struct GNUNET_CRYPTO_EddsaPrivateKey signkey_priv;
|
||||
struct GNUNET_CRYPTO_EddsaSignature signature;
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey master_pub;
|
||||
struct GNUNET_TIME_AbsoluteNBO start;
|
||||
struct GNUNET_TIME_AbsoluteNBO expire;
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey signkey_pub;
|
||||
};
|
||||
|
||||
struct TALER_MINT_DenomKeyIssue
|
||||
{
|
||||
/**
|
||||
* The private key of the denomination. Will be NULL if the private key is
|
||||
* not available.
|
||||
*/
|
||||
struct TALER_RSA_PrivateKey *denom_priv;
|
||||
struct GNUNET_CRYPTO_EddsaSignature signature;
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey master;
|
||||
struct GNUNET_TIME_AbsoluteNBO start;
|
||||
struct GNUNET_TIME_AbsoluteNBO expire_withdraw;
|
||||
struct GNUNET_TIME_AbsoluteNBO expire_spend;
|
||||
struct TALER_RSA_PublicKeyBinaryEncoded denom_pub;
|
||||
struct TALER_AmountNBO value;
|
||||
struct TALER_AmountNBO fee_withdraw;
|
||||
struct TALER_AmountNBO fee_deposit;
|
||||
struct TALER_AmountNBO fee_refresh;
|
||||
};
|
||||
|
||||
struct RefreshMeltSignatureBody
|
||||
{
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||
struct GNUNET_HashCode melt_hash;
|
||||
};
|
||||
|
||||
struct RefreshCommitSignatureBody
|
||||
{
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||
struct GNUNET_HashCode commit_hash;
|
||||
};
|
||||
|
||||
struct RefreshCommitResponseSignatureBody
|
||||
{
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||
uint16_t noreveal_index;
|
||||
};
|
||||
|
||||
struct RefreshMeltResponseSignatureBody
|
||||
{
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||
struct GNUNET_HashCode melt_response_hash;
|
||||
};
|
||||
|
||||
|
||||
struct RefreshMeltConfirmSignRequestBody
|
||||
{
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
|
||||
};
|
||||
|
||||
|
||||
GNUNET_NETWORK_STRUCT_END
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Iterator for sign keys.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param ski the sign key issue
|
||||
* @return #GNUNET_OK to continue to iterate,
|
||||
* #GNUNET_NO to stop iteration with no error,
|
||||
* #GNUNET_SYSERR to abort iteration with error!
|
||||
*/
|
||||
typedef int (*TALER_MINT_SignkeyIterator)(void *cls,
|
||||
const struct TALER_MINT_SignKeyIssue *ski);
|
||||
|
||||
/**
|
||||
* Iterator for denomination keys.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param dki the denomination key issue
|
||||
* @param alias coin alias
|
||||
* @return #GNUNET_OK to continue to iterate,
|
||||
* #GNUNET_NO to stop iteration with no error,
|
||||
* #GNUNET_SYSERR to abort iteration with error!
|
||||
*/
|
||||
typedef int (*TALER_MINT_DenomkeyIterator)(void *cls,
|
||||
const char *alias,
|
||||
const struct TALER_MINT_DenomKeyIssue *dki);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* FIXME
|
||||
*/
|
||||
int
|
||||
TALER_MINT_signkeys_iterate (const char *mint_base_dir,
|
||||
TALER_MINT_SignkeyIterator it, void *cls);
|
||||
|
||||
|
||||
/**
|
||||
* FIXME
|
||||
*/
|
||||
int
|
||||
TALER_MINT_denomkeys_iterate (const char *mint_base_dir,
|
||||
TALER_MINT_DenomkeyIterator it, void *cls);
|
||||
|
||||
|
||||
/**
|
||||
* Exports a denomination key to the given file
|
||||
*
|
||||
* @param filename the file where to write the denomination key
|
||||
* @param dki the denomination key
|
||||
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure.
|
||||
*/
|
||||
int
|
||||
TALER_MINT_write_denom_key (const char *filename,
|
||||
const struct TALER_MINT_DenomKeyIssue *dki);
|
||||
|
||||
|
||||
/**
|
||||
* Import a denomination key from the given file
|
||||
*
|
||||
* @param filename the file to import the key from
|
||||
* @param dki pointer to return the imported denomination key
|
||||
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
|
||||
*/
|
||||
int
|
||||
TALER_MINT_read_denom_key (const char *filename,
|
||||
struct TALER_MINT_DenomKeyIssue *dki);
|
||||
|
||||
|
||||
/**
|
||||
* Load the configuration for the mint in the given
|
||||
* directory.
|
||||
*
|
||||
* @param mint_base_dir the mint's base directory
|
||||
* @return the mint configuratin, or NULL on error
|
||||
*/
|
||||
struct GNUNET_CONFIGURATION_Handle *
|
||||
TALER_MINT_config_load (const char *mint_base_dir);
|
||||
|
||||
|
||||
int
|
||||
TALER_TALER_DB_extract_amount (PGresult *result, unsigned int row,
|
||||
int indices[3], struct TALER_Amount *denom);
|
||||
|
||||
int
|
||||
TALER_TALER_DB_extract_amount_nbo (PGresult *result, unsigned int row,
|
||||
int indices[3], struct TALER_AmountNBO *denom_nbo);
|
||||
|
||||
#endif /* _MINT_H */
|
||||
|
1121
src/mint/mint_api.c
Normal file
1121
src/mint/mint_api.c
Normal file
File diff suppressed because it is too large
Load Diff
283
src/mint/mint_common.c
Normal file
283
src/mint/mint_common.c
Normal file
@ -0,0 +1,283 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file mint_common.c
|
||||
* @brief Common functionality for the mint
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
* @author Sree Harsha Totakura
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#include "mint.h"
|
||||
|
||||
struct SignkeysIterateContext
|
||||
{
|
||||
TALER_MINT_SignkeyIterator it;
|
||||
void *it_cls;
|
||||
};
|
||||
|
||||
|
||||
struct DenomkeysIterateContext
|
||||
{
|
||||
const char *alias;
|
||||
TALER_MINT_DenomkeyIterator it;
|
||||
void *it_cls;
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
signkeys_iterate_dir_iter (void *cls,
|
||||
const char *filename)
|
||||
{
|
||||
|
||||
struct SignkeysIterateContext *skc = cls;
|
||||
ssize_t nread;
|
||||
struct TALER_MINT_SignKeyIssue issue;
|
||||
nread = GNUNET_DISK_fn_read (filename,
|
||||
&issue,
|
||||
sizeof (struct TALER_MINT_SignKeyIssue));
|
||||
if (nread != sizeof (struct TALER_MINT_SignKeyIssue))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid signkey file: '%s'\n", filename);
|
||||
return GNUNET_OK;
|
||||
}
|
||||
return skc->it (skc->it_cls, &issue);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
TALER_MINT_signkeys_iterate (const char *mint_base_dir,
|
||||
TALER_MINT_SignkeyIterator it, void *cls)
|
||||
{
|
||||
char *signkey_dir;
|
||||
size_t len;
|
||||
struct SignkeysIterateContext skc;
|
||||
|
||||
len = GNUNET_asprintf (&signkey_dir, ("%s" DIR_SEPARATOR_STR DIR_SIGNKEYS), mint_base_dir);
|
||||
GNUNET_assert (len > 0);
|
||||
|
||||
skc.it = it;
|
||||
skc.it_cls = cls;
|
||||
|
||||
return GNUNET_DISK_directory_scan (signkey_dir, &signkeys_iterate_dir_iter, &skc);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Import a denomination key from the given file
|
||||
*
|
||||
* @param filename the file to import the key from
|
||||
* @param dki pointer to return the imported denomination key
|
||||
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure
|
||||
*/
|
||||
int
|
||||
TALER_MINT_read_denom_key (const char *filename,
|
||||
struct TALER_MINT_DenomKeyIssue *dki)
|
||||
{
|
||||
uint64_t size;
|
||||
size_t offset;
|
||||
void *data;
|
||||
struct TALER_RSA_PrivateKey *priv;
|
||||
int ret;
|
||||
|
||||
ret = GNUNET_SYSERR;
|
||||
data = NULL;
|
||||
offset = sizeof (struct TALER_MINT_DenomKeyIssue)
|
||||
- offsetof (struct TALER_MINT_DenomKeyIssue, signature);
|
||||
if (GNUNET_OK != GNUNET_DISK_file_size (filename,
|
||||
&size,
|
||||
GNUNET_YES,
|
||||
GNUNET_YES))
|
||||
goto cleanup;
|
||||
if (size <= offset)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
goto cleanup;
|
||||
}
|
||||
data = GNUNET_malloc (size);
|
||||
if (size != GNUNET_DISK_fn_read (filename,
|
||||
data,
|
||||
size))
|
||||
goto cleanup;
|
||||
if (NULL == (priv = TALER_RSA_decode_key (data + offset, size - offset)))
|
||||
goto cleanup;
|
||||
dki->denom_priv = priv;
|
||||
(void) memcpy (&dki->signature, data, offset);
|
||||
ret = GNUNET_OK;
|
||||
|
||||
cleanup:
|
||||
GNUNET_free_non_null (data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Exports a denomination key to the given file
|
||||
*
|
||||
* @param filename the file where to write the denomination key
|
||||
* @param dki the denomination key
|
||||
* @return #GNUNET_OK upon success; #GNUNET_SYSERR upon failure.
|
||||
*/
|
||||
int
|
||||
TALER_MINT_write_denom_key (const char *filename,
|
||||
const struct TALER_MINT_DenomKeyIssue *dki)
|
||||
{
|
||||
struct TALER_RSA_PrivateKeyBinaryEncoded *priv_enc;
|
||||
struct GNUNET_DISK_FileHandle *fh;
|
||||
ssize_t wrote;
|
||||
size_t wsize;
|
||||
int ret;
|
||||
|
||||
fh = NULL;
|
||||
priv_enc = NULL;
|
||||
ret = GNUNET_SYSERR;
|
||||
if (NULL == (fh = GNUNET_DISK_file_open
|
||||
(filename,
|
||||
GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_CREATE | GNUNET_DISK_OPEN_TRUNCATE,
|
||||
GNUNET_DISK_PERM_USER_READ | GNUNET_DISK_PERM_USER_WRITE)))
|
||||
goto cleanup;
|
||||
if (NULL == (priv_enc = TALER_RSA_encode_key (dki->denom_priv)))
|
||||
goto cleanup;
|
||||
wsize = sizeof (struct TALER_MINT_DenomKeyIssue)
|
||||
- offsetof (struct TALER_MINT_DenomKeyIssue, signature);
|
||||
if (GNUNET_SYSERR == (wrote = GNUNET_DISK_file_write (fh,
|
||||
&dki->signature,
|
||||
wsize)))
|
||||
goto cleanup;
|
||||
if (wrote != wsize)
|
||||
goto cleanup;
|
||||
wsize = ntohs (priv_enc->len);
|
||||
if (GNUNET_SYSERR == (wrote = GNUNET_DISK_file_write (fh,
|
||||
priv_enc,
|
||||
wsize)))
|
||||
goto cleanup;
|
||||
if (wrote != wsize)
|
||||
goto cleanup;
|
||||
ret = GNUNET_OK;
|
||||
cleanup:
|
||||
GNUNET_free_non_null (priv_enc);
|
||||
if (NULL != fh)
|
||||
(void) GNUNET_DISK_file_close (fh);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
denomkeys_iterate_keydir_iter (void *cls,
|
||||
const char *filename)
|
||||
{
|
||||
|
||||
struct DenomkeysIterateContext *dic = cls;
|
||||
struct TALER_MINT_DenomKeyIssue issue;
|
||||
|
||||
if (GNUNET_OK != TALER_MINT_read_denom_key (filename, &issue))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Invalid denomkey file: '%s'\n", filename);
|
||||
return GNUNET_OK;
|
||||
}
|
||||
return dic->it (dic->it_cls, dic->alias, &issue);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
denomkeys_iterate_topdir_iter (void *cls,
|
||||
const char *filename)
|
||||
{
|
||||
|
||||
struct DenomkeysIterateContext *dic = cls;
|
||||
dic->alias = GNUNET_STRINGS_get_short_name (filename);
|
||||
|
||||
// FIXME: differentiate between error case and normal iteration abortion
|
||||
if (0 > GNUNET_DISK_directory_scan (filename, &denomkeys_iterate_keydir_iter, dic))
|
||||
return GNUNET_SYSERR;
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
TALER_MINT_denomkeys_iterate (const char *mint_base_dir,
|
||||
TALER_MINT_DenomkeyIterator it, void *cls)
|
||||
{
|
||||
char *dir;
|
||||
size_t len;
|
||||
struct DenomkeysIterateContext dic;
|
||||
len = GNUNET_asprintf (&dir, ("%s" DIR_SEPARATOR_STR DIR_DENOMKEYS),
|
||||
mint_base_dir);
|
||||
GNUNET_assert (len > 0);
|
||||
|
||||
dic.it = it;
|
||||
dic.it_cls = cls;
|
||||
|
||||
// scan over alias dirs
|
||||
return GNUNET_DISK_directory_scan (dir, &denomkeys_iterate_topdir_iter, &dic);
|
||||
}
|
||||
|
||||
|
||||
struct GNUNET_CONFIGURATION_Handle *
|
||||
TALER_MINT_config_load (const char *mint_base_dir)
|
||||
{
|
||||
struct GNUNET_CONFIGURATION_Handle *cfg;
|
||||
char *cfg_dir;
|
||||
int res;
|
||||
|
||||
res = GNUNET_asprintf (&cfg_dir, "%s" DIR_SEPARATOR_STR "config", mint_base_dir);
|
||||
GNUNET_assert (res > 0);
|
||||
|
||||
cfg = GNUNET_CONFIGURATION_create ();
|
||||
res = GNUNET_CONFIGURATION_load_from (cfg, cfg_dir);
|
||||
GNUNET_free (cfg_dir);
|
||||
if (GNUNET_OK != res)
|
||||
return NULL;
|
||||
return cfg;
|
||||
}
|
||||
|
||||
int
|
||||
TALER_TALER_DB_extract_amount_nbo (PGresult *result, unsigned int row,
|
||||
int indices[3], struct TALER_AmountNBO *denom_nbo)
|
||||
{
|
||||
if ((indices[0] < 0) || (indices[1] < 0) || (indices[2] < 0))
|
||||
return GNUNET_NO;
|
||||
if (sizeof (uint32_t) != PQgetlength (result, row, indices[0]))
|
||||
return GNUNET_SYSERR;
|
||||
if (sizeof (uint32_t) != PQgetlength (result, row, indices[1]))
|
||||
return GNUNET_SYSERR;
|
||||
if (PQgetlength (result, row, indices[2]) > TALER_CURRENCY_LEN)
|
||||
return GNUNET_SYSERR;
|
||||
denom_nbo->value = *(uint32_t *) PQgetvalue (result, row, indices[0]);
|
||||
denom_nbo->fraction = *(uint32_t *) PQgetvalue (result, row, indices[1]);
|
||||
memset (denom_nbo->currency, 0, TALER_CURRENCY_LEN);
|
||||
memcpy (denom_nbo->currency, PQgetvalue (result, row, indices[2]), PQgetlength (result, row, indices[2]));
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
TALER_TALER_DB_extract_amount (PGresult *result, unsigned int row,
|
||||
int indices[3], struct TALER_Amount *denom)
|
||||
{
|
||||
struct TALER_AmountNBO denom_nbo;
|
||||
int res;
|
||||
|
||||
res = TALER_TALER_DB_extract_amount_nbo (result, row, indices, &denom_nbo);
|
||||
if (GNUNET_OK != res)
|
||||
return res;
|
||||
*denom = TALER_amount_ntoh (denom_nbo);
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
/* end of mint_common.c */
|
1838
src/mint/mint_db.c
Normal file
1838
src/mint/mint_db.c
Normal file
File diff suppressed because it is too large
Load Diff
344
src/mint/mint_db.h
Normal file
344
src/mint/mint_db.h
Normal file
@ -0,0 +1,344 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file mint/mint_db.h
|
||||
* @brief Mint-specific database access
|
||||
* @author Florian Dold
|
||||
*/
|
||||
|
||||
#ifndef _NEURO_MINT_DB_H
|
||||
#define _NEURO_MINT_DB_H
|
||||
|
||||
#include <libpq-fe.h>
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include "taler_util.h"
|
||||
#include "taler_types.h"
|
||||
#include "taler_rsa.h"
|
||||
|
||||
|
||||
/**
|
||||
* Reserve row. Corresponds to table 'reserves' in
|
||||
* the mint's database.
|
||||
*/
|
||||
struct Reserve
|
||||
{
|
||||
/**
|
||||
* Signature over the purse.
|
||||
* Only valid if (blind_session_missing==GNUNET_YES).
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EddsaSignature status_sig;
|
||||
/**
|
||||
* Signature with purpose TALER_SIGNATURE_PURSE.
|
||||
* Only valid if (blind_session_missing==GNUNET_YES).
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EccSignaturePurpose status_sig_purpose;
|
||||
/**
|
||||
* Signing key used to sign the purse.
|
||||
* Only valid if (blind_session_missing==GNUNET_YES).
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey status_sign_pub;
|
||||
/**
|
||||
* Withdraw public key, identifies the purse.
|
||||
* Only the customer knows the corresponding private key.
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
|
||||
/**
|
||||
* Remaining balance in the purse.
|
||||
*/
|
||||
struct TALER_AmountNBO balance;
|
||||
|
||||
/**
|
||||
* Expiration date for the purse.
|
||||
*/
|
||||
struct GNUNET_TIME_AbsoluteNBO expiration;
|
||||
};
|
||||
|
||||
|
||||
struct CollectableBlindcoin
|
||||
{
|
||||
struct TALER_RSA_BlindedSignaturePurpose ev;
|
||||
struct TALER_RSA_Signature ev_sig;
|
||||
struct TALER_RSA_PublicKeyBinaryEncoded denom_pub;
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
|
||||
struct GNUNET_CRYPTO_EddsaSignature reserve_sig;
|
||||
};
|
||||
|
||||
|
||||
struct RefreshSession
|
||||
{
|
||||
int has_commit_sig;
|
||||
struct GNUNET_CRYPTO_EddsaSignature commit_sig;
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
|
||||
uint16_t num_oldcoins;
|
||||
uint16_t num_newcoins;
|
||||
uint16_t kappa;
|
||||
uint16_t noreveal_index;
|
||||
uint8_t reveal_ok;
|
||||
};
|
||||
|
||||
|
||||
#define TALER_REFRESH_SHARED_SECRET_LENGTH (sizeof (struct GNUNET_HashCode))
|
||||
#define TALER_REFRESH_LINK_LENGTH (sizeof (struct LinkData))
|
||||
|
||||
struct RefreshCommitLink
|
||||
{
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
|
||||
struct GNUNET_CRYPTO_EcdsaPublicKey transfer_pub;
|
||||
uint16_t cnc_index;
|
||||
uint16_t oldcoin_index;
|
||||
char shared_secret_enc[sizeof (struct GNUNET_HashCode)];
|
||||
};
|
||||
|
||||
struct LinkData
|
||||
{
|
||||
struct GNUNET_CRYPTO_EcdsaPrivateKey coin_priv;
|
||||
struct TALER_RSA_BlindingKeyBinaryEncoded bkey_enc;
|
||||
};
|
||||
|
||||
|
||||
GNUNET_NETWORK_STRUCT_BEGIN
|
||||
|
||||
struct SharedSecretEnc
|
||||
{
|
||||
char data[TALER_REFRESH_SHARED_SECRET_LENGTH];
|
||||
};
|
||||
|
||||
|
||||
struct LinkDataEnc
|
||||
{
|
||||
char data[sizeof (struct LinkData)];
|
||||
};
|
||||
|
||||
GNUNET_NETWORK_STRUCT_END
|
||||
|
||||
struct RefreshCommitCoin
|
||||
{
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey session_pub;
|
||||
struct TALER_RSA_BlindedSignaturePurpose coin_ev;
|
||||
uint16_t cnc_index;
|
||||
uint16_t newcoin_index;
|
||||
char link_enc[sizeof (struct LinkData)];
|
||||
};
|
||||
|
||||
|
||||
struct KnownCoin
|
||||
{
|
||||
struct TALER_CoinPublicInfo public_info;
|
||||
struct TALER_Amount expended_balance;
|
||||
int is_refreshed;
|
||||
/**
|
||||
* Refreshing session, only valid if
|
||||
* is_refreshed==1.
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey refresh_session_pub;
|
||||
};
|
||||
|
||||
GNUNET_NETWORK_STRUCT_BEGIN
|
||||
|
||||
struct Deposit
|
||||
{
|
||||
/* FIXME: should be TALER_CoinPublicInfo */
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey coin_pub;
|
||||
struct TALER_RSA_PublicKeyBinaryEncoded denom_pub;
|
||||
struct TALER_RSA_Signature coin_sig;
|
||||
struct TALER_RSA_SignaturePurpose purpose;
|
||||
uint64_t transaction_id;
|
||||
struct TALER_AmountNBO amount;
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey merchant_pub;
|
||||
struct GNUNET_HashCode h_contract;
|
||||
struct GNUNET_HashCode h_wire;
|
||||
/* TODO: uint16_t wire_size */
|
||||
char wire[]; /* string encoded wire JSON object */
|
||||
};
|
||||
|
||||
GNUNET_NETWORK_STRUCT_END
|
||||
|
||||
int
|
||||
TALER_MINT_DB_prepare (PGconn *db_conn);
|
||||
|
||||
int
|
||||
TALER_MINT_DB_get_collectable_blindcoin (PGconn *db_conn,
|
||||
struct TALER_RSA_BlindedSignaturePurpose *blind_ev,
|
||||
struct CollectableBlindcoin *collectable);
|
||||
|
||||
int
|
||||
TALER_MINT_DB_insert_collectable_blindcoin (PGconn *db_conn,
|
||||
const struct CollectableBlindcoin *collectable);
|
||||
|
||||
|
||||
int
|
||||
TALER_MINT_DB_rollback (PGconn *db_conn);
|
||||
|
||||
|
||||
int
|
||||
TALER_MINT_DB_transaction (PGconn *db_conn);
|
||||
|
||||
|
||||
int
|
||||
TALER_MINT_DB_commit (PGconn *db_conn);
|
||||
|
||||
|
||||
int
|
||||
TALER_MINT_DB_get_reserve (PGconn *db_conn,
|
||||
const struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub,
|
||||
struct Reserve *reserve_res);
|
||||
|
||||
int
|
||||
TALER_MINT_DB_update_reserve (PGconn *db_conn,
|
||||
const struct Reserve *reserve,
|
||||
int fresh);
|
||||
|
||||
|
||||
int
|
||||
TALER_MINT_DB_insert_refresh_order (PGconn *db_conn,
|
||||
uint16_t newcoin_index,
|
||||
const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
|
||||
const struct TALER_RSA_PublicKeyBinaryEncoded *denom_pub);
|
||||
|
||||
int
|
||||
TALER_MINT_DB_get_refresh_session (PGconn *db_conn,
|
||||
const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
|
||||
struct RefreshSession *r_session);
|
||||
|
||||
|
||||
int
|
||||
TALER_MINT_DB_get_known_coin (PGconn *db_conn, struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
|
||||
struct KnownCoin *known_coin);
|
||||
|
||||
|
||||
int
|
||||
TALER_MINT_DB_upsert_known_coin (PGconn *db_conn, struct KnownCoin *known_coin);
|
||||
|
||||
|
||||
int
|
||||
TALER_MINT_DB_insert_refresh_commit_link (PGconn *db_conn, struct RefreshCommitLink *commit_link);
|
||||
|
||||
int
|
||||
TALER_MINT_DB_insert_refresh_commit_coin (PGconn *db_conn, struct RefreshCommitCoin *commit_coin);
|
||||
|
||||
|
||||
int
|
||||
TALER_MINT_DB_get_refresh_commit_link (PGconn *db_conn,
|
||||
const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
|
||||
int i, int j,
|
||||
struct RefreshCommitLink *commit_link);
|
||||
|
||||
|
||||
int
|
||||
TALER_MINT_DB_get_refresh_commit_coin (PGconn *db_conn,
|
||||
const struct GNUNET_CRYPTO_EddsaPublicKey *refresh_session_pub,
|
||||
int i, int j,
|
||||
struct RefreshCommitCoin *commit_coin);
|
||||
|
||||
|
||||
int
|
||||
TALER_MINT_DB_create_refresh_session (PGconn *db_conn,
|
||||
const struct GNUNET_CRYPTO_EddsaPublicKey
|
||||
*session_pub);
|
||||
|
||||
|
||||
int
|
||||
TALER_MINT_DB_get_refresh_order (PGconn *db_conn,
|
||||
uint16_t newcoin_index,
|
||||
const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
|
||||
struct TALER_RSA_PublicKeyBinaryEncoded *denom_pub);
|
||||
|
||||
|
||||
int
|
||||
TALER_MINT_DB_insert_refresh_collectable (PGconn *db_conn,
|
||||
uint16_t newcoin_index,
|
||||
const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
|
||||
const struct TALER_RSA_Signature *ev_sig);
|
||||
int
|
||||
TALER_MINT_DB_get_refresh_collectable (PGconn *db_conn,
|
||||
uint16_t newcoin_index,
|
||||
const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
|
||||
struct TALER_RSA_Signature *ev_sig);
|
||||
int
|
||||
TALER_MINT_DB_set_reveal_ok (PGconn *db_conn,
|
||||
const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub);
|
||||
|
||||
int
|
||||
TALER_MINT_DB_insert_refresh_melt (PGconn *db_conn,
|
||||
const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
|
||||
uint16_t oldcoin_index,
|
||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
|
||||
const struct TALER_RSA_PublicKeyBinaryEncoded *denom_pub);
|
||||
|
||||
|
||||
int
|
||||
TALER_MINT_DB_get_refresh_melt (PGconn *db_conn,
|
||||
const struct GNUNET_CRYPTO_EddsaPublicKey *session_pub,
|
||||
uint16_t oldcoin_index,
|
||||
struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub);
|
||||
|
||||
|
||||
typedef
|
||||
int (*LinkIterator) (void *cls,
|
||||
const struct LinkDataEnc *link_data_enc,
|
||||
const struct TALER_RSA_PublicKeyBinaryEncoded *denom_pub,
|
||||
const struct TALER_RSA_Signature *ev_sig);
|
||||
|
||||
int
|
||||
TALER_db_get_link (PGconn *db_conn,
|
||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
|
||||
LinkIterator link_iter,
|
||||
void *cls);
|
||||
|
||||
|
||||
int
|
||||
TALER_db_get_transfer (PGconn *db_conn,
|
||||
const struct GNUNET_CRYPTO_EcdsaPublicKey *coin_pub,
|
||||
struct GNUNET_CRYPTO_EcdsaPublicKey *transfer_pub,
|
||||
struct SharedSecretEnc *shared_secret_enc);
|
||||
|
||||
int
|
||||
TALER_MINT_DB_init_deposits (PGconn *db_conn, int temporary);
|
||||
|
||||
int
|
||||
TALER_MINT_DB_prepare_deposits (PGconn *db_conn);
|
||||
|
||||
int
|
||||
TALER_MINT_DB_insert_deposit (PGconn *db_conn,
|
||||
const struct Deposit *deposit);
|
||||
|
||||
int
|
||||
TALER_MINT_DB_get_deposit (PGconn *db_conn,
|
||||
const struct GNUNET_CRYPTO_EddsaPublicKey *coin_pub,
|
||||
struct Deposit **r_deposit);
|
||||
int
|
||||
TALER_MINT_DB_insert_known_coin (PGconn *db_conn,
|
||||
const struct KnownCoin *known_coin);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the thread-local database-handle.
|
||||
* Connect to the db if the connection does not exist yet.
|
||||
*
|
||||
* @param the database connection, or NULL on error
|
||||
*/
|
||||
PGconn *
|
||||
TALER_MINT_DB_get_connection (void);
|
||||
|
||||
|
||||
int
|
||||
TALER_MINT_DB_init (const char *connection_cfg);
|
||||
|
||||
|
||||
|
||||
#endif /* _NEURO_MINT_DB_H */
|
285
src/mint/taler-mint-dbinit.c
Normal file
285
src/mint/taler-mint-dbinit.c
Normal file
@ -0,0 +1,285 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file taler-mint-dbinit.c
|
||||
* @brief Create tables for the mint database.
|
||||
* @author Florian Dold
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <libpq-fe.h>
|
||||
#include "mint.h"
|
||||
|
||||
|
||||
#define break_db_err(result) do { \
|
||||
GNUNET_break(0); \
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Database failure: %s\n", PQresultErrorMessage (result)); \
|
||||
PQclear (result); \
|
||||
} while (0)
|
||||
|
||||
|
||||
static char *mint_base_dir;
|
||||
static struct GNUNET_CONFIGURATION_Handle *cfg;
|
||||
static PGconn *db_conn;
|
||||
static char *TALER_MINT_db_connection_cfg_str;
|
||||
|
||||
|
||||
int
|
||||
TALER_MINT_init_withdraw_tables (PGconn *conn)
|
||||
{
|
||||
PGresult *result;
|
||||
result = PQexec (conn,
|
||||
"CREATE TABLE IF NOT EXISTS reserves"
|
||||
"("
|
||||
" reserve_pub BYTEA PRIMARY KEY"
|
||||
",balance_value INT4 NOT NULL"
|
||||
",balance_fraction INT4 NOT NULL"
|
||||
",balance_currency VARCHAR(4) NOT NULL"
|
||||
",status_sig BYTEA"
|
||||
",status_sign_pub BYTEA"
|
||||
",expiration_date INT8 NOT NULL"
|
||||
")");
|
||||
if (PGRES_COMMAND_OK != PQresultStatus(result))
|
||||
{
|
||||
break_db_err (result);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
PQclear (result);
|
||||
|
||||
result = PQexec (conn,
|
||||
"CREATE TABLE IF NOT EXISTS collectable_blindcoins"
|
||||
"("
|
||||
"blind_ev BYTEA PRIMARY KEY"
|
||||
",blind_ev_sig BYTEA NOT NULL"
|
||||
",denom_pub BYTEA NOT NULL"
|
||||
",reserve_sig BYTEA NOT NULL"
|
||||
",reserve_pub BYTEA NOT NULL REFERENCES reserves (reserve_pub)"
|
||||
")");
|
||||
if (PGRES_COMMAND_OK != PQresultStatus(result))
|
||||
{
|
||||
break_db_err (result);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
PQclear (result);
|
||||
|
||||
result = PQexec (conn,
|
||||
"CREATE TABLE IF NOT EXISTS known_coins "
|
||||
"("
|
||||
" coin_pub BYTEA NOT NULL PRIMARY KEY"
|
||||
",denom_pub BYTEA NOT NULL"
|
||||
",denom_sig BYTEA NOT NULL"
|
||||
",expended_value INT4 NOT NULL"
|
||||
",expended_fraction INT4 NOT NULL"
|
||||
",expended_currency VARCHAR(4) NOT NULL"
|
||||
",refresh_session_pub BYTEA"
|
||||
")");
|
||||
if (PGRES_COMMAND_OK != PQresultStatus(result))
|
||||
{
|
||||
break_db_err (result);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
PQclear (result);
|
||||
|
||||
result = PQexec (conn,
|
||||
"CREATE TABLE IF NOT EXISTS refresh_sessions "
|
||||
"("
|
||||
" session_pub BYTEA PRIMARY KEY CHECK (length(session_pub) = 32)"
|
||||
",session_melt_sig BYTEA"
|
||||
",session_commit_sig BYTEA"
|
||||
",noreveal_index INT2 NOT NULL"
|
||||
// non-zero if all reveals were ok
|
||||
// and the new coin signatures are ready
|
||||
",reveal_ok BOOLEAN NOT NULL DEFAULT false"
|
||||
") ");
|
||||
if (PGRES_COMMAND_OK != PQresultStatus(result))
|
||||
{
|
||||
break_db_err (result);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
PQclear (result);
|
||||
|
||||
result = PQexec (conn,
|
||||
"CREATE TABLE IF NOT EXISTS refresh_order "
|
||||
"( "
|
||||
" session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub)"
|
||||
",newcoin_index INT2 NOT NULL "
|
||||
",denom_pub BYTEA NOT NULL "
|
||||
",PRIMARY KEY (session_pub, newcoin_index)"
|
||||
") ");
|
||||
|
||||
if (PGRES_COMMAND_OK != PQresultStatus(result))
|
||||
{
|
||||
break_db_err (result);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
PQclear (result);
|
||||
|
||||
|
||||
result = PQexec (conn,
|
||||
"CREATE TABLE IF NOT EXISTS refresh_commit_link"
|
||||
"("
|
||||
" session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub)"
|
||||
",transfer_pub BYTEA NOT NULL"
|
||||
",link_secret_enc BYTEA NOT NULL"
|
||||
// index of the old coin in the customer's request
|
||||
",oldcoin_index INT2 NOT NULL"
|
||||
// index for cut and choose,
|
||||
// ranges from 0 to kappa-1
|
||||
",cnc_index INT2 NOT NULL"
|
||||
")");
|
||||
|
||||
if (PGRES_COMMAND_OK != PQresultStatus(result))
|
||||
{
|
||||
break_db_err (result);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
PQclear (result);
|
||||
|
||||
result = PQexec (conn,
|
||||
"CREATE TABLE IF NOT EXISTS refresh_commit_coin"
|
||||
"("
|
||||
" session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub) "
|
||||
",link_vector_enc BYTEA NOT NULL"
|
||||
// index of the new coin in the customer's request
|
||||
",newcoin_index INT2 NOT NULL"
|
||||
// index for cut and choose,
|
||||
",cnc_index INT2 NOT NULL"
|
||||
",coin_ev BYTEA NOT NULL"
|
||||
")");
|
||||
|
||||
if (PGRES_COMMAND_OK != PQresultStatus(result))
|
||||
{
|
||||
break_db_err (result);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
PQclear (result);
|
||||
|
||||
result = PQexec (conn,
|
||||
"CREATE TABLE IF NOT EXISTS refresh_melt"
|
||||
"("
|
||||
" session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub) "
|
||||
",coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) "
|
||||
",denom_pub BYTEA NOT NULL "
|
||||
",oldcoin_index INT2 NOT NULL"
|
||||
")");
|
||||
|
||||
if (PGRES_COMMAND_OK != PQresultStatus(result))
|
||||
{
|
||||
break_db_err (result);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
PQclear (result);
|
||||
|
||||
result = PQexec (conn,
|
||||
"CREATE TABLE IF NOT EXISTS refresh_collectable"
|
||||
"("
|
||||
" session_pub BYTEA NOT NULL REFERENCES refresh_sessions (session_pub) "
|
||||
",ev_sig BYTEA NOT NULL"
|
||||
",newcoin_index INT2 NOT NULL"
|
||||
")");
|
||||
|
||||
if (PGRES_COMMAND_OK != PQresultStatus(result))
|
||||
{
|
||||
break_db_err (result);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
PQclear (result);
|
||||
|
||||
result = PQexec (conn,
|
||||
"CREATE TABLE IF NOT EXISTS deposits "
|
||||
"( "
|
||||
" coin_pub BYTEA NOT NULL PRIMARY KEY CHECK (length(coin_pub)=32)"
|
||||
",denom_pub BYTEA NOT NULL CHECK (length(denom_pub)=32)"
|
||||
",transaction_id INT8 NOT NULL"
|
||||
",amount_currency VARCHAR(4) NOT NULL"
|
||||
",amount_value INT4 NOT NULL"
|
||||
",amount_fraction INT4 NOT NULL"
|
||||
",merchant_pub BYTEA NOT NULL"
|
||||
",h_contract BYTEA NOT NULL CHECK (length(h_contract)=64)"
|
||||
",h_wire BYTEA NOT NULL CHECK (length(h_wire)=64)"
|
||||
",coin_sig BYTEA NOT NULL CHECK (length(coin_sig)=64)"
|
||||
",wire TEXT NOT NULL"
|
||||
")");
|
||||
|
||||
if (PGRES_COMMAND_OK != PQresultStatus(result))
|
||||
{
|
||||
break_db_err (result);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
PQclear (result);
|
||||
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The main function of the serve tool
|
||||
*
|
||||
* @param argc number of arguments from the command line
|
||||
* @param argv command line arguments
|
||||
* @return 0 ok, 1 on error
|
||||
*/
|
||||
int
|
||||
main (int argc, char *const *argv)
|
||||
{
|
||||
static const struct GNUNET_GETOPT_CommandLineOption options[] = {
|
||||
GNUNET_GETOPT_OPTION_HELP ("gnunet-mint-keyup OPTIONS"),
|
||||
{'d', "mint-dir", "DIR",
|
||||
"mint directory", 1,
|
||||
&GNUNET_GETOPT_set_filename, &mint_base_dir},
|
||||
GNUNET_GETOPT_OPTION_END
|
||||
};
|
||||
|
||||
if (GNUNET_GETOPT_run ("taler-mint-serve", options, argc, argv) < 0)
|
||||
return 1;
|
||||
|
||||
GNUNET_assert (GNUNET_OK == GNUNET_log_setup ("taler-mint-dbinit", "INFO", NULL));
|
||||
|
||||
if (NULL == mint_base_dir)
|
||||
{
|
||||
fprintf (stderr, "Mint base directory not given.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
cfg = TALER_MINT_config_load (mint_base_dir);
|
||||
if (NULL == cfg)
|
||||
{
|
||||
fprintf (stderr, "Can't load mint configuration.\n");
|
||||
return 1;
|
||||
}
|
||||
if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "mint", "db", &TALER_MINT_db_connection_cfg_str))
|
||||
{
|
||||
fprintf (stderr, "Configuration 'mint.db' not found.\n");
|
||||
return 42;
|
||||
}
|
||||
db_conn = PQconnectdb (TALER_MINT_db_connection_cfg_str);
|
||||
if (CONNECTION_OK != PQstatus (db_conn))
|
||||
{
|
||||
fprintf (stderr, "Database connection failed: %s\n", PQerrorMessage (db_conn));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (GNUNET_OK != TALER_MINT_init_withdraw_tables (db_conn))
|
||||
{
|
||||
fprintf (stderr, "Failed to initialize database.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
376
src/mint/taler-mint-httpd.c
Normal file
376
src/mint/taler-mint-httpd.c
Normal file
@ -0,0 +1,376 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 GNUnet e.V.
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file taler-mint-httpd.c
|
||||
* @brief Serve the HTTP interface of the mint
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <jansson.h>
|
||||
#include <microhttpd.h>
|
||||
#include <libpq-fe.h>
|
||||
#include <pthread.h>
|
||||
#include "mint.h"
|
||||
#include "mint_db.h"
|
||||
#include "taler_types.h"
|
||||
#include "taler_signatures.h"
|
||||
#include "taler_rsa.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_microhttpd_lib.h"
|
||||
#include "taler-mint-httpd_mhd.h"
|
||||
#include "taler-mint-httpd_keys.h"
|
||||
#include "taler-mint-httpd_deposit.h"
|
||||
#include "taler-mint-httpd_withdraw.h"
|
||||
#include "taler-mint-httpd_refresh.h"
|
||||
|
||||
|
||||
/**
|
||||
* Base directory of the mint (global)
|
||||
*/
|
||||
char *mintdir;
|
||||
|
||||
/**
|
||||
* The mint's configuration (global)
|
||||
*/
|
||||
struct GNUNET_CONFIGURATION_Handle *cfg;
|
||||
|
||||
/**
|
||||
* Master public key (according to the
|
||||
* configuration in the mint directory).
|
||||
*/
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey master_pub;
|
||||
|
||||
/**
|
||||
* The HTTP Daemon.
|
||||
*/
|
||||
static struct MHD_Daemon *mydaemon;
|
||||
|
||||
/**
|
||||
* The kappa value for refreshing.
|
||||
*/
|
||||
static unsigned int refresh_security_parameter;
|
||||
|
||||
/**
|
||||
* Port to run the daemon on.
|
||||
*/
|
||||
static uint16_t serve_port;
|
||||
|
||||
|
||||
/**
|
||||
* Convert a string representing an EdDSA signature to an EdDSA
|
||||
* signature.
|
||||
*
|
||||
* FIXME: this should be in GNUnet.
|
||||
* FIXME: why? this code is dead, even here!
|
||||
*
|
||||
* @param enc encoded EdDSA signature
|
||||
* @param enclen number of bytes in @a enc (without 0-terminator)
|
||||
* @param pub where to store the EdDSA signature
|
||||
* @return #GNUNET_OK on success
|
||||
*/
|
||||
int
|
||||
TALER_eddsa_signature_from_string (const char *enc,
|
||||
size_t enclen,
|
||||
struct GNUNET_CRYPTO_EddsaSignature *sig)
|
||||
{
|
||||
size_t keylen = (sizeof (struct GNUNET_CRYPTO_EddsaSignature)) * 8;
|
||||
|
||||
if (keylen % 5 > 0)
|
||||
keylen += 5 - keylen % 5;
|
||||
keylen /= 5;
|
||||
if (enclen != keylen)
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
|
||||
sig,
|
||||
sizeof (struct GNUNET_CRYPTO_EddsaSignature)))
|
||||
return GNUNET_SYSERR;
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle a request coming from libmicrohttpd.
|
||||
*
|
||||
* @param cls closure for MHD daemon (unused)
|
||||
* @param connection the connection
|
||||
* @param url the requested url
|
||||
* @param method the method (POST, GET, ...)
|
||||
* @param upload_data request data
|
||||
* @param upload_data_size size of @a upload_data in bytes
|
||||
* @param con_cls closure for request (a `struct Buffer *`)
|
||||
* @return MHD result code
|
||||
*/
|
||||
static int
|
||||
handle_mhd_request (void *cls,
|
||||
struct MHD_Connection *connection,
|
||||
const char *url,
|
||||
const char *method,
|
||||
const char *version,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size,
|
||||
void **con_cls)
|
||||
{
|
||||
static struct RequestHandler handlers[] =
|
||||
{
|
||||
{ "/", MHD_HTTP_METHOD_GET, "text/plain",
|
||||
"Hello, I'm the mint\n", 0,
|
||||
&TALER_MINT_handler_static_response, MHD_HTTP_OK },
|
||||
{ "/agpl", MHD_HTTP_METHOD_GET, "text/plain",
|
||||
NULL, 0,
|
||||
&TALER_MINT_handler_agpl_redirect, MHD_HTTP_FOUND },
|
||||
{ "/keys", MHD_HTTP_METHOD_GET, "application/json",
|
||||
NULL, 0,
|
||||
&TALER_MINT_handler_keys, MHD_HTTP_OK },
|
||||
{ "/keys", NULL, "text/plain",
|
||||
"Only GET is allowed", 0,
|
||||
&TALER_MINT_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
|
||||
{ "/withdraw/status", MHD_HTTP_METHOD_GET, "application/json",
|
||||
NULL, 0,
|
||||
&TALER_MINT_handler_withdraw_status, MHD_HTTP_OK },
|
||||
{ "/withdraw/status", NULL, "text/plain",
|
||||
"Only GET is allowed", 0,
|
||||
&TALER_MINT_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
|
||||
{ "/withdraw/sign", MHD_HTTP_METHOD_GET, "application/json",
|
||||
NULL, 0,
|
||||
&TALER_MINT_handler_withdraw_sign, MHD_HTTP_OK },
|
||||
{ "/withdraw/sign", NULL, "text/plain",
|
||||
"Only GET is allowed", 0,
|
||||
&TALER_MINT_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
|
||||
{ "/refresh/melt", MHD_HTTP_METHOD_POST, "application/json",
|
||||
NULL, 0,
|
||||
&TALER_MINT_handler_refresh_melt, MHD_HTTP_OK },
|
||||
{ "/refresh/melt", NULL, "text/plain",
|
||||
"Only POST is allowed", 0,
|
||||
&TALER_MINT_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
|
||||
{ "/refresh/commit", MHD_HTTP_METHOD_POST, "application/json",
|
||||
NULL, 0,
|
||||
&TALER_MINT_handler_refresh_commit, MHD_HTTP_OK },
|
||||
{ "/refresh/commit", NULL, "text/plain",
|
||||
"Only POST is allowed", 0,
|
||||
&TALER_MINT_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
|
||||
{ "/refresh/reveal", MHD_HTTP_METHOD_POST, "application/json",
|
||||
NULL, 0,
|
||||
&TALER_MINT_handler_refresh_melt, MHD_HTTP_OK },
|
||||
{ "/refresh/reveal", NULL, "text/plain",
|
||||
"Only POST is allowed", 0,
|
||||
&TALER_MINT_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
|
||||
{ "/refresh/link", MHD_HTTP_METHOD_GET, "application/json",
|
||||
NULL, 0,
|
||||
&TALER_MINT_handler_refresh_link, MHD_HTTP_OK },
|
||||
{ "/refresh/link", NULL, "text/plain",
|
||||
"Only GET is allowed", 0,
|
||||
&TALER_MINT_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
|
||||
{ "/refresh/reveal", MHD_HTTP_METHOD_GET, "application/json",
|
||||
NULL, 0,
|
||||
&TALER_MINT_handler_refresh_reveal, MHD_HTTP_OK },
|
||||
{ "/refresh/reveal", NULL, "text/plain",
|
||||
"Only GET is allowed", 0,
|
||||
&TALER_MINT_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
|
||||
{ "/deposit", MHD_HTTP_METHOD_POST, "application/json",
|
||||
NULL, 0,
|
||||
&TALER_MINT_handler_deposit, MHD_HTTP_OK },
|
||||
{ "/deposit", NULL, "text/plain",
|
||||
"Only POST is allowed", 0,
|
||||
&TALER_MINT_handler_send_json_pack_error, MHD_HTTP_METHOD_NOT_ALLOWED },
|
||||
{ NULL, NULL, NULL, NULL, 0, 0 }
|
||||
};
|
||||
static struct RequestHandler h404 =
|
||||
{
|
||||
"", NULL, "text/html",
|
||||
"<html><title>404: not found</title></html>", 0,
|
||||
&TALER_MINT_handler_static_response, MHD_HTTP_NOT_FOUND
|
||||
};
|
||||
struct RequestHandler *rh;
|
||||
unsigned int i;
|
||||
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"Handling request for URL '%s'\n",
|
||||
url);
|
||||
for (i=0;NULL != handlers[i].url;i++)
|
||||
{
|
||||
rh = &handlers[i];
|
||||
if ( (0 == strcasecmp (url,
|
||||
rh->url)) &&
|
||||
( (NULL == rh->method) ||
|
||||
(0 == strcasecmp (method,
|
||||
rh->method)) ) )
|
||||
return rh->handler (rh,
|
||||
connection,
|
||||
con_cls,
|
||||
upload_data,
|
||||
upload_data_size);
|
||||
}
|
||||
return TALER_MINT_handler_static_response (&h404,
|
||||
connection,
|
||||
con_cls,
|
||||
upload_data,
|
||||
upload_data_size);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Load configuration parameters for the mint
|
||||
* server into the corresponding global variables.
|
||||
*
|
||||
* @param param mint_directory the mint's directory
|
||||
* @return GNUNET_OK on success
|
||||
*/
|
||||
static int
|
||||
mint_serve_process_config (const char *mint_directory)
|
||||
{
|
||||
unsigned long long port;
|
||||
unsigned long long kappa;
|
||||
char *master_pub_str;
|
||||
char *db_cfg;
|
||||
|
||||
cfg = TALER_MINT_config_load (mint_directory);
|
||||
if (NULL == cfg)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"can't load mint configuration\n");
|
||||
return 1;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CONFIGURATION_get_value_string (cfg,
|
||||
"mint", "master_pub",
|
||||
&master_pub_str))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"No master public key given in mint configuration.");
|
||||
return GNUNET_NO;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CRYPTO_eddsa_public_key_from_string (master_pub_str,
|
||||
strlen (master_pub_str),
|
||||
&master_pub))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Invalid master public key given in mint configuration.");
|
||||
return GNUNET_NO;
|
||||
}
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CONFIGURATION_get_value_string (cfg,
|
||||
"mint", "db",
|
||||
&db_cfg))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"invalid configuration: mint.db\n");
|
||||
return GNUNET_NO;
|
||||
}
|
||||
if (GNUNET_OK !=
|
||||
TALER_MINT_DB_init (db_cfg))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"failed to initialize DB subsystem\n");
|
||||
return GNUNET_NO;
|
||||
}
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CONFIGURATION_get_value_number (cfg,
|
||||
"mint", "port",
|
||||
&port))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"invalid configuration: mint.port\n");
|
||||
return GNUNET_NO;
|
||||
}
|
||||
|
||||
if ((port == 0) || (port > UINT16_MAX))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"invalid configuration (value out of range): mint.port\n");
|
||||
return GNUNET_NO;
|
||||
}
|
||||
serve_port = port;
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CONFIGURATION_get_value_number (cfg,
|
||||
"mint", "refresh_security_parameter",
|
||||
&kappa))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"invalid configuration: mint.refresh_security_parameter\n");
|
||||
return GNUNET_NO;
|
||||
}
|
||||
refresh_security_parameter = kappa;
|
||||
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The main function of the serve tool
|
||||
*
|
||||
* @param argc number of arguments from the command line
|
||||
* @param argv command line arguments
|
||||
* @return 0 ok, 1 on error
|
||||
*/
|
||||
int
|
||||
main (int argc, char *const *argv)
|
||||
{
|
||||
static const struct GNUNET_GETOPT_CommandLineOption options[] = {
|
||||
GNUNET_GETOPT_OPTION_HELP ("gnunet-mint-keyup OPTIONS"),
|
||||
{'d', "mint-dir", "DIR",
|
||||
"mint directory", 1,
|
||||
&GNUNET_GETOPT_set_filename, &mintdir},
|
||||
GNUNET_GETOPT_OPTION_END
|
||||
};
|
||||
int ret;
|
||||
|
||||
GNUNET_assert (GNUNET_OK ==
|
||||
GNUNET_log_setup ("taler-mint-serve",
|
||||
"INFO",
|
||||
NULL));
|
||||
if (GNUNET_GETOPT_run ("taler-mint-serve",
|
||||
options,
|
||||
argc, argv) < 0)
|
||||
return 1;
|
||||
if (NULL == mintdir)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"no mint dir given\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (GNUNET_OK != mint_serve_process_config (mintdir))
|
||||
return 1;
|
||||
|
||||
|
||||
mydaemon = MHD_start_daemon (MHD_USE_SELECT_INTERNALLY | MHD_USE_DEBUG,
|
||||
serve_port,
|
||||
NULL, NULL,
|
||||
&handle_mhd_request, NULL,
|
||||
MHD_OPTION_END);
|
||||
|
||||
if (NULL == mydaemon)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failed to start MHD.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = TALER_MINT_key_reload_loop ();
|
||||
MHD_stop_daemon (mydaemon);
|
||||
return (GNUNET_OK == ret) ? 0 : 1;
|
||||
}
|
||||
|
106
src/mint/taler-mint-httpd.h
Normal file
106
src/mint/taler-mint-httpd.h
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 GNUnet e.V.
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file taler-mint-httpd.h
|
||||
* @brief Global declarations for the mint
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef TALER_MINT_HTTPD_H
|
||||
#define TALER_MINT_HTTPD_H
|
||||
|
||||
|
||||
/**
|
||||
* Cut-and-choose size for refreshing.
|
||||
* FIXME: maybe make it a config option?
|
||||
*/
|
||||
#define KAPPA 3
|
||||
|
||||
|
||||
/**
|
||||
* The mint's configuration.
|
||||
*/
|
||||
extern struct GNUNET_CONFIGURATION_Handle *cfg;
|
||||
|
||||
/**
|
||||
* Main directory with mint data.
|
||||
*/
|
||||
extern char *mintdir;
|
||||
|
||||
/**
|
||||
* Master public key (according to the
|
||||
* configuration in the mint directory).
|
||||
*/
|
||||
extern struct GNUNET_CRYPTO_EddsaPublicKey master_pub;
|
||||
|
||||
|
||||
/**
|
||||
* Struct describing an URL and the handler for it.
|
||||
*/
|
||||
struct RequestHandler
|
||||
{
|
||||
|
||||
/**
|
||||
* URL the handler is for.
|
||||
*/
|
||||
const char *url;
|
||||
|
||||
/**
|
||||
* Method the handler is for, NULL for "all".
|
||||
*/
|
||||
const char *method;
|
||||
|
||||
/**
|
||||
* Mime type to use in reply (hint, can be NULL).
|
||||
*/
|
||||
const char *mime_type;
|
||||
|
||||
/**
|
||||
* Raw data for the @e handler
|
||||
*/
|
||||
const void *data;
|
||||
|
||||
/**
|
||||
* Number of bytes in @e data, 0 for 0-terminated.
|
||||
*/
|
||||
size_t data_size;
|
||||
|
||||
/**
|
||||
* Function to call to handle the request.
|
||||
*
|
||||
* @param rh this struct
|
||||
* @param mime_type the @e mime_type for the reply (hint, can be NULL)
|
||||
* @param connection the MHD connection to handle
|
||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||
* @param upload_data upload data
|
||||
* @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
|
||||
* @return MHD result code
|
||||
*/
|
||||
int (*handler)(struct RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
void **connection_cls,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size);
|
||||
|
||||
/**
|
||||
* Default response code.
|
||||
*/
|
||||
int response_code;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
270
src/mint/taler-mint-httpd_deposit.c
Normal file
270
src/mint/taler-mint-httpd_deposit.c
Normal file
@ -0,0 +1,270 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 GNUnet e.V.
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file taler-mint-httpd_deposit.c
|
||||
* @brief Handle /deposit requests
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <jansson.h>
|
||||
#include <microhttpd.h>
|
||||
#include <libpq-fe.h>
|
||||
#include <pthread.h>
|
||||
#include "mint.h"
|
||||
#include "mint_db.h"
|
||||
#include "taler_types.h"
|
||||
#include "taler_signatures.h"
|
||||
#include "taler_rsa.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_microhttpd_lib.h"
|
||||
#include "taler-mint-httpd_keys.h"
|
||||
#include "taler-mint-httpd_deposit.h"
|
||||
|
||||
|
||||
/**
|
||||
* Send confirmation of deposit success to client.
|
||||
*
|
||||
* @param connection connection to the client
|
||||
* @param deposit deposit request to confirm
|
||||
* @return MHD result code
|
||||
*/
|
||||
static int
|
||||
helper_deposit_send_response_success (struct MHD_Connection *connection,
|
||||
struct Deposit *deposit)
|
||||
{
|
||||
// FIXME: return more information here
|
||||
return request_send_json_pack (connection, MHD_HTTP_OK,
|
||||
"{s:s}", "status", "DEPOSIT_OK");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle a "/deposit" request
|
||||
*
|
||||
* @param rh context of the handler
|
||||
* @param connection the MHD connection to handle
|
||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||
* @param upload_data upload data
|
||||
* @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TALER_MINT_handler_deposit (struct RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
void **connection_cls,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size)
|
||||
{
|
||||
json_t *json;
|
||||
struct Deposit *deposit;
|
||||
json_t *wire;
|
||||
json_t *resp;
|
||||
char *wire_enc = NULL;
|
||||
const char *deposit_type;
|
||||
struct MintKeyState *key_state;
|
||||
struct TALER_CoinPublicInfo coin_info;
|
||||
struct TALER_RSA_Signature ubsig;
|
||||
size_t len;
|
||||
int resp_code;
|
||||
PGconn *db_conn;
|
||||
int res;
|
||||
|
||||
res = process_post_json (connection,
|
||||
connection_cls,
|
||||
upload_data, upload_data_size,
|
||||
&json);
|
||||
if (GNUNET_SYSERR == res)
|
||||
{
|
||||
// FIXME: return 'internal error'
|
||||
GNUNET_break (0);
|
||||
return MHD_NO;
|
||||
}
|
||||
if (GNUNET_NO == res)
|
||||
return MHD_YES;
|
||||
if (NULL == (db_conn = TALER_MINT_DB_get_connection ()))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
deposit = NULL;
|
||||
wire = NULL;
|
||||
resp = NULL;
|
||||
if (-1 == json_unpack (json,
|
||||
"{s:s s:o}",
|
||||
"type", &deposit_type,
|
||||
"wire", &wire))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
resp = json_pack ("{s:s}", "error", "Bad format");
|
||||
resp_code = MHD_HTTP_BAD_REQUEST;
|
||||
goto EXITIF_exit;
|
||||
}
|
||||
if (NULL == (wire_enc = json_dumps (wire, JSON_COMPACT|JSON_SORT_KEYS)))
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
resp = json_pack ("{s:s}", "error", "Bad format");
|
||||
resp_code = MHD_HTTP_BAD_REQUEST;
|
||||
goto EXITIF_exit;
|
||||
}
|
||||
len = strlen (wire_enc) + 1;
|
||||
deposit = GNUNET_malloc (sizeof (struct Deposit) + len);
|
||||
#define EXITIF(cond) \
|
||||
do { \
|
||||
if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
|
||||
} while (0)
|
||||
#define PARSE_DATA(field, addr) \
|
||||
EXITIF (GNUNET_OK != request_json_require_nav \
|
||||
(connection, json, \
|
||||
JNAV_FIELD, field, JNAV_RET_DATA, addr, sizeof (*addr)))
|
||||
PARSE_DATA ("coin_pub", &deposit->coin_pub);
|
||||
PARSE_DATA ("denom_pub", &deposit->denom_pub);
|
||||
PARSE_DATA ("ubsig", &ubsig);
|
||||
PARSE_DATA ("merchant_pub", &deposit->merchant_pub);
|
||||
PARSE_DATA ("H_a", &deposit->h_contract);
|
||||
PARSE_DATA ("H_wire", &deposit->h_wire);
|
||||
PARSE_DATA ("csig", &deposit->coin_sig);
|
||||
PARSE_DATA ("transaction_id", &deposit->transaction_id);
|
||||
#undef PARSE_DATA
|
||||
if (0 == strcmp ("DIRECT_DEPOSIT", deposit_type))
|
||||
deposit->purpose.purpose = htonl (TALER_SIGNATURE_DEPOSIT);
|
||||
else if (0 == strcmp ("INCREMENTAL_DEPOSIT", deposit_type))
|
||||
deposit->purpose.purpose = htonl (TALER_SIGNATURE_INCREMENTAL_DEPOSIT);
|
||||
else
|
||||
{
|
||||
GNUNET_break_op (0);
|
||||
resp = json_pack ("{s:s}", "error", "Bad format");
|
||||
resp_code = MHD_HTTP_BAD_REQUEST;
|
||||
goto EXITIF_exit;
|
||||
}
|
||||
deposit->purpose.size = htonl (sizeof (struct Deposit)
|
||||
- offsetof (struct Deposit, purpose));
|
||||
memcpy (&coin_info.coin_pub,
|
||||
&deposit->coin_pub,
|
||||
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey));
|
||||
coin_info.denom_pub = deposit->denom_pub;
|
||||
coin_info.denom_sig = ubsig;
|
||||
key_state = TALER_MINT_key_state_acquire ();
|
||||
if (GNUNET_YES != TALER_MINT_test_coin_valid (key_state,
|
||||
&coin_info))
|
||||
{
|
||||
TALER_MINT_key_state_release (key_state);
|
||||
resp = json_pack ("{s:s}", "error", "Coin is not valid");
|
||||
resp_code = MHD_HTTP_NOT_FOUND;
|
||||
goto EXITIF_exit;
|
||||
}
|
||||
TALER_MINT_key_state_release (key_state);
|
||||
/*
|
||||
if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_DEPOSIT,
|
||||
&deposit->purpose,
|
||||
&deposit->coin_sig,
|
||||
&deposit->coin_pub))
|
||||
{
|
||||
resp = json_pack ("{s:s}", "error", "Signature verfication failed");
|
||||
resp_code = MHD_HTTP_NOT_FOUND;
|
||||
goto EXITIF_exit;
|
||||
}
|
||||
*/
|
||||
|
||||
/* Check if we already received the same deposit permission,
|
||||
* or the coin was already deposited */
|
||||
|
||||
{
|
||||
struct Deposit *existing_deposit;
|
||||
int res;
|
||||
|
||||
res = TALER_MINT_DB_get_deposit (db_conn,
|
||||
&deposit->coin_pub,
|
||||
&existing_deposit);
|
||||
if (GNUNET_YES == res)
|
||||
{
|
||||
// FIXME: memory leak
|
||||
if (0 == memcmp (existing_deposit, deposit, sizeof (struct Deposit)))
|
||||
return helper_deposit_send_response_success (connection, deposit);
|
||||
// FIXME: in the future, check if there's enough credits
|
||||
// left on the coin. For now: refuse
|
||||
// FIXME: return more information here
|
||||
return request_send_json_pack (connection, MHD_HTTP_FORBIDDEN,
|
||||
"{s:s}",
|
||||
"error", "double spending");
|
||||
}
|
||||
|
||||
if (GNUNET_SYSERR == res)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
struct KnownCoin known_coin;
|
||||
int res;
|
||||
|
||||
res = TALER_MINT_DB_get_known_coin (db_conn, &coin_info.coin_pub, &known_coin);
|
||||
if (GNUNET_YES == res)
|
||||
{
|
||||
// coin must have been refreshed
|
||||
// FIXME: check
|
||||
// FIXME: return more information here
|
||||
return request_send_json_pack (connection, MHD_HTTP_FORBIDDEN,
|
||||
"{s:s}",
|
||||
"error", "coin was refreshed");
|
||||
}
|
||||
if (GNUNET_SYSERR == res)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
/* coin valid but not known => insert into DB */
|
||||
known_coin.is_refreshed = GNUNET_NO;
|
||||
known_coin.expended_balance = TALER_amount_ntoh (deposit->amount);
|
||||
known_coin.public_info = coin_info;
|
||||
|
||||
if (GNUNET_OK != TALER_MINT_DB_insert_known_coin (db_conn, &known_coin))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
}
|
||||
|
||||
if (GNUNET_OK != TALER_MINT_DB_insert_deposit (db_conn, deposit))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
return helper_deposit_send_response_success (connection, deposit);
|
||||
|
||||
EXITIF_exit:
|
||||
if (NULL != resp)
|
||||
res = send_response_json (connection, resp, resp_code);
|
||||
else
|
||||
res = MHD_NO;
|
||||
if (NULL != wire)
|
||||
json_decref (wire);
|
||||
if (NULL != deposit)
|
||||
GNUNET_free (deposit);
|
||||
if (NULL != wire_enc)
|
||||
GNUNET_free (wire_enc);
|
||||
return res;
|
||||
#undef EXITIF
|
||||
#undef PARSE_DATA
|
||||
}
|
||||
|
||||
/* end of taler-mint-httpd_deposit.c */
|
48
src/mint/taler-mint-httpd_deposit.h
Normal file
48
src/mint/taler-mint-httpd_deposit.h
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 GNUnet e.V.
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file taler-mint-httpd_deposit.h
|
||||
* @brief Handle /deposit requests
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef TALER_MINT_HTTPD_DEPOSIT_H
|
||||
#define TALER_MINT_HTTPD_DEPOSIT_H
|
||||
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <microhttpd.h>
|
||||
#include "taler-mint-httpd.h"
|
||||
|
||||
|
||||
/**
|
||||
* Handle a "/deposit" request
|
||||
*
|
||||
* @param rh context of the handler
|
||||
* @param connection the MHD connection to handle
|
||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||
* @param upload_data upload data
|
||||
* @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TALER_MINT_handler_deposit (struct RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
void **connection_cls,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size);
|
||||
|
||||
#endif
|
512
src/mint/taler-mint-httpd_keys.c
Normal file
512
src/mint/taler-mint-httpd_keys.c
Normal file
@ -0,0 +1,512 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 GNUnet e.V.
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file taler-mint-httpd_keys.c
|
||||
* @brief Handle /keys requests
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <jansson.h>
|
||||
#include <microhttpd.h>
|
||||
#include <libpq-fe.h>
|
||||
#include <pthread.h>
|
||||
#include "mint.h"
|
||||
#include "mint_db.h"
|
||||
#include "taler_types.h"
|
||||
#include "taler_signatures.h"
|
||||
#include "taler_rsa.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_microhttpd_lib.h"
|
||||
#include "taler-mint-httpd_keys.h"
|
||||
|
||||
|
||||
/**
|
||||
* Mint key state. Never use directly, instead access via
|
||||
* #TALER_MINT_key_state_acquire and #TALER_MINT_key_state_release.
|
||||
*/
|
||||
static struct MintKeyState *internal_key_state;
|
||||
|
||||
/**
|
||||
* Mutex protecting access to #internal_key_state.
|
||||
*/
|
||||
static pthread_mutex_t internal_key_state_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/**
|
||||
* Pipe used for signaling reloading of our key state.
|
||||
*/
|
||||
static int reload_pipe[2];
|
||||
|
||||
|
||||
/**
|
||||
* Convert the public part of a denomination key
|
||||
* issue to a JSON object.
|
||||
*
|
||||
* @param dki the denomination key issue
|
||||
* @return a JSON object describing the denomination key isue (public part)
|
||||
*/
|
||||
static json_t *
|
||||
denom_key_issue_to_json (const struct TALER_MINT_DenomKeyIssue *dki)
|
||||
{
|
||||
json_t *dk_json = json_object ();
|
||||
json_object_set_new (dk_json, "master_sig",
|
||||
TALER_JSON_from_data (&dki->signature, sizeof (struct GNUNET_CRYPTO_EddsaSignature)));
|
||||
json_object_set_new (dk_json, "stamp_start", TALER_JSON_from_abs (GNUNET_TIME_absolute_ntoh (dki->start)));
|
||||
json_object_set_new (dk_json, "stamp_expire_withdraw", TALER_JSON_from_abs (GNUNET_TIME_absolute_ntoh (dki->expire_withdraw)));
|
||||
json_object_set_new (dk_json, "stamp_expire_deposit", TALER_JSON_from_abs (GNUNET_TIME_absolute_ntoh (dki->expire_spend)));
|
||||
json_object_set_new (dk_json, "denom_pub",
|
||||
TALER_JSON_from_data (&dki->denom_pub, sizeof (struct TALER_RSA_PublicKeyBinaryEncoded)));
|
||||
json_object_set_new (dk_json, "value",
|
||||
TALER_JSON_from_amount (TALER_amount_ntoh (dki->value)));
|
||||
json_object_set_new (dk_json,
|
||||
"fee_withdraw",
|
||||
TALER_JSON_from_amount(TALER_amount_ntoh (dki->fee_withdraw)));
|
||||
json_object_set_new (dk_json,
|
||||
"fee_deposit",
|
||||
TALER_JSON_from_amount(TALER_amount_ntoh (dki->fee_deposit)));
|
||||
json_object_set_new (dk_json,
|
||||
"fee_refresh",
|
||||
TALER_JSON_from_amount(TALER_amount_ntoh (dki->fee_refresh)));
|
||||
return dk_json;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert the public part of a sign key
|
||||
* issue to a JSON object.
|
||||
*
|
||||
* @param ski the sign key issue
|
||||
* @return a JSON object describing the sign key isue (public part)
|
||||
*/
|
||||
static json_t *
|
||||
sign_key_issue_to_json (const struct TALER_MINT_SignKeyIssue *ski)
|
||||
{
|
||||
json_t *sk_json = json_object ();
|
||||
json_object_set_new (sk_json, "stamp_start", TALER_JSON_from_abs (GNUNET_TIME_absolute_ntoh (ski->start)));
|
||||
json_object_set_new (sk_json, "stamp_expire", TALER_JSON_from_abs (GNUNET_TIME_absolute_ntoh (ski->expire)));
|
||||
json_object_set_new (sk_json, "master_sig",
|
||||
TALER_JSON_from_data (&ski->signature, sizeof (struct GNUNET_CRYPTO_EddsaSignature)));
|
||||
json_object_set_new (sk_json, "key",
|
||||
TALER_JSON_from_data (&ski->signkey_pub, sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)));
|
||||
return sk_json;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the relative time value that describes how
|
||||
* far in the future do we want to provide coin keys.
|
||||
*
|
||||
* @return the provide duration
|
||||
*/
|
||||
static struct GNUNET_TIME_Relative
|
||||
TALER_MINT_conf_duration_provide ()
|
||||
{
|
||||
struct GNUNET_TIME_Relative rel;
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CONFIGURATION_get_value_time (cfg,
|
||||
"mint_keys",
|
||||
"lookahead_provide",
|
||||
&rel))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
|
||||
"mint_keys.lookahead_provide not valid or not given\n");
|
||||
GNUNET_abort ();
|
||||
}
|
||||
return rel;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Iterator for denomination keys.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param dki the denomination key issue
|
||||
* @param alias coin alias
|
||||
* @return #GNUNET_OK to continue to iterate,
|
||||
* #GNUNET_NO to stop iteration with no error,
|
||||
* #GNUNET_SYSERR to abort iteration with error!
|
||||
*/
|
||||
static int
|
||||
reload_keys_denom_iter (void *cls,
|
||||
const char *alias,
|
||||
const struct TALER_MINT_DenomKeyIssue *dki)
|
||||
{
|
||||
struct MintKeyState *ctx = cls;
|
||||
struct GNUNET_TIME_Absolute stamp_provide;
|
||||
struct GNUNET_HashCode denom_key_hash;
|
||||
int res;
|
||||
|
||||
stamp_provide = GNUNET_TIME_absolute_add (ctx->reload_time,
|
||||
TALER_MINT_conf_duration_provide ());
|
||||
|
||||
if (GNUNET_TIME_absolute_ntoh (dki->expire_spend).abs_value_us < ctx->reload_time.abs_value_us)
|
||||
{
|
||||
// this key is expired
|
||||
return GNUNET_OK;
|
||||
}
|
||||
if (GNUNET_TIME_absolute_ntoh (dki->start).abs_value_us > stamp_provide.abs_value_us)
|
||||
{
|
||||
// we are to early for this key
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
GNUNET_CRYPTO_hash (&dki->denom_pub, sizeof (struct GNUNET_CRYPTO_EddsaPublicKey), &denom_key_hash);
|
||||
|
||||
res = GNUNET_CONTAINER_multihashmap_put (ctx->denomkey_map,
|
||||
&denom_key_hash,
|
||||
GNUNET_memdup (dki, sizeof (struct TALER_MINT_DenomKeyIssue)),
|
||||
GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
|
||||
if (GNUNET_OK != res)
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Duplicate denomination key\n");
|
||||
|
||||
json_array_append_new (ctx->denom_keys_array,
|
||||
denom_key_issue_to_json (dki));
|
||||
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Iterator for sign keys.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param ski the sign key issue
|
||||
* @return #GNUNET_OK to continue to iterate,
|
||||
* #GNUNET_NO to stop iteration with no error,
|
||||
* #GNUNET_SYSERR to abort iteration with error!
|
||||
*/
|
||||
static int
|
||||
reload_keys_sign_iter (void *cls,
|
||||
const struct TALER_MINT_SignKeyIssue *ski)
|
||||
{
|
||||
struct MintKeyState *ctx = cls;
|
||||
struct GNUNET_TIME_Absolute stamp_provide;
|
||||
|
||||
stamp_provide = GNUNET_TIME_absolute_add (ctx->reload_time, TALER_MINT_conf_duration_provide (cfg));
|
||||
|
||||
if (GNUNET_TIME_absolute_ntoh (ski->expire).abs_value_us < ctx->reload_time.abs_value_us)
|
||||
{
|
||||
// this key is expired
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
if (GNUNET_TIME_absolute_ntoh (ski->start).abs_value_us > stamp_provide.abs_value_us)
|
||||
{
|
||||
// we are to early for this key
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
// the signkey is valid for now, check
|
||||
// if it's more recent than the current one!
|
||||
if (GNUNET_TIME_absolute_ntoh (ctx->current_sign_key_issue.start).abs_value_us >
|
||||
GNUNET_TIME_absolute_ntoh (ski->start).abs_value_us)
|
||||
ctx->current_sign_key_issue = *ski;
|
||||
|
||||
|
||||
ctx->next_reload = GNUNET_TIME_absolute_min (ctx->next_reload,
|
||||
GNUNET_TIME_absolute_ntoh (ski->expire));
|
||||
|
||||
json_array_append_new (ctx->sign_keys_array,
|
||||
sign_key_issue_to_json (ski));
|
||||
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load the mint's key state from disk.
|
||||
*
|
||||
* @return fresh key state (with reference count 1)
|
||||
*/
|
||||
static struct MintKeyState *
|
||||
reload_keys ()
|
||||
{
|
||||
struct MintKeyState *key_state;
|
||||
json_t *keys;
|
||||
|
||||
key_state = GNUNET_new (struct MintKeyState);
|
||||
key_state->refcnt = 1;
|
||||
|
||||
key_state->next_reload = GNUNET_TIME_UNIT_FOREVER_ABS;
|
||||
|
||||
key_state->denom_keys_array = json_array ();
|
||||
GNUNET_assert (NULL != key_state->denom_keys_array);
|
||||
|
||||
key_state->sign_keys_array = json_array ();
|
||||
GNUNET_assert (NULL != key_state->sign_keys_array);
|
||||
|
||||
key_state->denomkey_map = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_NO);
|
||||
GNUNET_assert (NULL != key_state->denomkey_map);
|
||||
|
||||
key_state->reload_time = GNUNET_TIME_absolute_get ();
|
||||
|
||||
TALER_MINT_denomkeys_iterate (mintdir, &reload_keys_denom_iter, key_state);
|
||||
TALER_MINT_signkeys_iterate (mintdir, &reload_keys_sign_iter, key_state);
|
||||
|
||||
keys = json_pack ("{s:o, s:o, s:o, s:o}",
|
||||
"master_pub", TALER_JSON_from_data (&master_pub, sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)),
|
||||
"signkeys", key_state->sign_keys_array,
|
||||
"denoms", key_state->denom_keys_array,
|
||||
"list_issue_date", TALER_JSON_from_abs (key_state->reload_time));
|
||||
|
||||
key_state->keys_json = json_dumps (keys, JSON_INDENT(2));
|
||||
|
||||
return key_state;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Release key state, free if necessary (if reference count gets to zero).
|
||||
*
|
||||
* @param key_state the key state to release
|
||||
*/
|
||||
void
|
||||
TALER_MINT_key_state_release (struct MintKeyState *key_state)
|
||||
{
|
||||
GNUNET_assert (0 == pthread_mutex_lock (&internal_key_state_mutex));
|
||||
GNUNET_assert (0 != key_state->refcnt);
|
||||
key_state->refcnt += 1;
|
||||
if (key_state->refcnt == 0) {
|
||||
GNUNET_free (key_state);
|
||||
}
|
||||
GNUNET_assert (0 == pthread_mutex_unlock (&internal_key_state_mutex));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Acquire the key state of the mint. Updates keys if necessary.
|
||||
* For every call to #TALER_MINT_key_state_acquire, a matching call
|
||||
* to #TALER_MINT_key_state_release must be made.
|
||||
*
|
||||
* @return the key state
|
||||
*/
|
||||
struct MintKeyState *
|
||||
TALER_MINT_key_state_acquire (void)
|
||||
{
|
||||
struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
|
||||
struct MintKeyState *key_state;
|
||||
|
||||
// FIXME: the locking we have is very coarse-grained,
|
||||
// using multiple locks might be nicer ...
|
||||
|
||||
GNUNET_assert (0 == pthread_mutex_lock (&internal_key_state_mutex));
|
||||
if (NULL == internal_key_state)
|
||||
{
|
||||
internal_key_state = reload_keys ();
|
||||
}
|
||||
else if (internal_key_state->next_reload.abs_value_us <= now.abs_value_us)
|
||||
{
|
||||
GNUNET_assert (0 != internal_key_state->refcnt);
|
||||
internal_key_state->refcnt--;
|
||||
if (0 == internal_key_state->refcnt)
|
||||
GNUNET_free (internal_key_state);
|
||||
internal_key_state = reload_keys ();
|
||||
}
|
||||
key_state = internal_key_state;
|
||||
key_state->refcnt += 1;
|
||||
GNUNET_assert (0 == pthread_mutex_unlock (&internal_key_state_mutex));
|
||||
|
||||
return key_state;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Look up the issue for a denom public key.
|
||||
*
|
||||
* @param key state to look in
|
||||
* @param denom_pub denomination public key
|
||||
* @return the denomination key issue,
|
||||
* or NULL if denom_pub could not be found
|
||||
*/
|
||||
struct TALER_MINT_DenomKeyIssue *
|
||||
TALER_MINT_get_denom_key (const struct MintKeyState *key_state,
|
||||
const struct TALER_RSA_PublicKeyBinaryEncoded *denom_pub)
|
||||
{
|
||||
struct TALER_MINT_DenomKeyIssue *issue;
|
||||
struct GNUNET_HashCode hash;
|
||||
|
||||
GNUNET_CRYPTO_hash (denom_pub, sizeof (struct TALER_RSA_PublicKeyBinaryEncoded), &hash);
|
||||
issue = GNUNET_CONTAINER_multihashmap_get (key_state->denomkey_map, &hash);
|
||||
return issue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if a coin is valid; that is, whether the denomination key exists,
|
||||
* is not expired, and the signature is correct.
|
||||
*
|
||||
* @param key_state the key state to use for checking the coin's validity
|
||||
* @param coin_public_info the coin public info to check for validity
|
||||
* @return GNUNET_YES if the coin is valid,
|
||||
* GNUNET_NO if it is invalid
|
||||
* GNUNET_SYSERROR if an internal error occured
|
||||
*/
|
||||
int
|
||||
TALER_MINT_test_coin_valid (const struct MintKeyState *key_state,
|
||||
struct TALER_CoinPublicInfo *coin_public_info)
|
||||
{
|
||||
struct TALER_MINT_DenomKeyIssue *dki;
|
||||
|
||||
dki = TALER_MINT_get_denom_key (key_state, &coin_public_info->denom_pub);
|
||||
if (NULL == dki)
|
||||
return GNUNET_NO;
|
||||
if (GNUNET_OK != TALER_RSA_verify (&coin_public_info->coin_pub,
|
||||
sizeof (struct GNUNET_CRYPTO_EcdsaPublicKey),
|
||||
&coin_public_info->denom_sig,
|
||||
&dki->denom_pub))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
|
||||
"coin signature is invalid\n");
|
||||
return GNUNET_NO;
|
||||
}
|
||||
return GNUNET_YES;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to call to handle the request by sending
|
||||
* back static data from the @a rh.
|
||||
*
|
||||
* @param rh context of the handler
|
||||
* @param connection the MHD connection to handle
|
||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||
* @param upload_data upload data
|
||||
* @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TALER_MINT_handler_keys (struct RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
void **connection_cls,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size)
|
||||
{
|
||||
struct MintKeyState *key_state;
|
||||
struct MHD_Response *response;
|
||||
int ret;
|
||||
|
||||
key_state = TALER_MINT_key_state_acquire ();
|
||||
response = MHD_create_response_from_buffer (strlen (key_state->keys_json),
|
||||
key_state->keys_json,
|
||||
MHD_RESPMEM_MUST_COPY);
|
||||
TALER_MINT_key_state_release (key_state);
|
||||
if (NULL == response)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return MHD_NO;
|
||||
}
|
||||
(void) MHD_add_response_header (response,
|
||||
"Content-Type",
|
||||
rh->mime_type);
|
||||
ret = MHD_queue_response (connection,
|
||||
rh->response_code,
|
||||
response);
|
||||
MHD_destroy_response (response);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle a signal, writing relevant signal numbers
|
||||
* (currently just SIGUSR1) to a pipe.
|
||||
*
|
||||
* @param signal_number the signal number
|
||||
*/
|
||||
static void
|
||||
handle_signal (int signal_number)
|
||||
{
|
||||
size_t res;
|
||||
char c = signal_number;
|
||||
|
||||
if (SIGUSR1 == signal_number)
|
||||
{
|
||||
errno = 0;
|
||||
res = write (reload_pipe[1], &c, 1);
|
||||
if ((res < 0) && (EINTR != errno))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return;
|
||||
}
|
||||
if (0 == res)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read signals from a pipe in a loop, and reload keys from disk if
|
||||
* SIGUSR1 is read from the pipe.
|
||||
*/
|
||||
int
|
||||
TALER_MINT_key_reload_loop (void)
|
||||
{
|
||||
struct sigaction act;
|
||||
|
||||
if (0 != pipe (reload_pipe))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failed to create pipe.\n");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
memset (&act, 0, sizeof (struct sigaction));
|
||||
act.sa_handler = &handle_signal;
|
||||
|
||||
if (0 != sigaction (SIGUSR1, &act, NULL))
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Failed to set signal handler.\n");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
char c;
|
||||
ssize_t res;
|
||||
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
|
||||
"(re-)loading keys\n");
|
||||
GNUNET_assert (0 == pthread_mutex_lock (&internal_key_state_mutex));
|
||||
if (NULL != internal_key_state)
|
||||
{
|
||||
GNUNET_assert (0 != internal_key_state->refcnt);
|
||||
internal_key_state->refcnt -= 1;
|
||||
if (0 == internal_key_state->refcnt)
|
||||
GNUNET_free (internal_key_state);
|
||||
}
|
||||
internal_key_state = reload_keys ();
|
||||
GNUNET_assert (0 == pthread_mutex_unlock (&internal_key_state_mutex));
|
||||
read_again:
|
||||
errno = 0;
|
||||
res = read (reload_pipe[0], &c, 1);
|
||||
if ((res < 0) && (EINTR != errno))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (EINTR == errno)
|
||||
goto read_again;
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/* end of taler-mint-httpd_keys.c */
|
155
src/mint/taler-mint-httpd_keys.h
Normal file
155
src/mint/taler-mint-httpd_keys.h
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 GNUnet e.V.
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file taler-mint-httpd_keys.h
|
||||
* @brief Handle /keys requests and manage key state
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef TALER_MINT_HTTPD_KEYS_H
|
||||
#define TALER_MINT_HTTPD_KEYS_H
|
||||
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <microhttpd.h>
|
||||
#include "taler-mint-httpd.h"
|
||||
|
||||
|
||||
/**
|
||||
* Snapshot of the (coin and signing)
|
||||
* keys (including private keys) of the mint.
|
||||
*/
|
||||
struct MintKeyState
|
||||
{
|
||||
/**
|
||||
* When did we initiate the key reloading?
|
||||
*/
|
||||
struct GNUNET_TIME_Absolute reload_time;
|
||||
|
||||
/**
|
||||
* JSON array with denomination keys.
|
||||
*/
|
||||
json_t *denom_keys_array;
|
||||
|
||||
/**
|
||||
* JSON array with signing keys.
|
||||
*/
|
||||
json_t *sign_keys_array;
|
||||
|
||||
/**
|
||||
* Mapping from denomination keys to denomination key issue struct.
|
||||
*/
|
||||
struct GNUNET_CONTAINER_MultiHashMap *denomkey_map;
|
||||
|
||||
/**
|
||||
* When is the next key invalid and we have to reload?
|
||||
*/
|
||||
struct GNUNET_TIME_Absolute next_reload;
|
||||
|
||||
/**
|
||||
* Mint signing key that should be used currently.
|
||||
*/
|
||||
struct TALER_MINT_SignKeyIssue current_sign_key_issue;
|
||||
|
||||
/**
|
||||
* Cached JSON text that the mint will send for
|
||||
* a /keys request.
|
||||
*/
|
||||
char *keys_json;
|
||||
|
||||
/**
|
||||
* Reference count.
|
||||
*/
|
||||
unsigned int refcnt;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Release key state, free if necessary (if reference count gets to zero).
|
||||
*
|
||||
* @param key_state the key state to release
|
||||
*/
|
||||
void
|
||||
TALER_MINT_key_state_release (struct MintKeyState *key_state);
|
||||
|
||||
|
||||
/**
|
||||
* Acquire the key state of the mint. Updates keys if necessary.
|
||||
* For every call to #TALER_MINT_key_state_acquire, a matching call
|
||||
* to #TALER_MINT_key_state_release must be made.
|
||||
*
|
||||
* @return the key state
|
||||
*/
|
||||
struct MintKeyState *
|
||||
TALER_MINT_key_state_acquire (void);
|
||||
|
||||
|
||||
/**
|
||||
* Look up the issue for a denom public key.
|
||||
*
|
||||
* @param key state to look in
|
||||
* @param denom_pub denomination public key
|
||||
* @return the denomination key issue,
|
||||
* or NULL if denom_pub could not be found
|
||||
*/
|
||||
struct TALER_MINT_DenomKeyIssue *
|
||||
TALER_MINT_get_denom_key (const struct MintKeyState *key_state,
|
||||
const struct TALER_RSA_PublicKeyBinaryEncoded *denom_pub);
|
||||
|
||||
|
||||
/**
|
||||
* Check if a coin is valid; that is, whether the denomination key exists,
|
||||
* is not expired, and the signature is correct.
|
||||
*
|
||||
* @param key_state the key state to use for checking the coin's validity
|
||||
* @param coin_public_info the coin public info to check for validity
|
||||
* @return GNUNET_YES if the coin is valid,
|
||||
* GNUNET_NO if it is invalid
|
||||
* GNUNET_SYSERROR if an internal error occured
|
||||
*/
|
||||
int
|
||||
TALER_MINT_test_coin_valid (const struct MintKeyState *key_state,
|
||||
struct TALER_CoinPublicInfo *coin_public_info);
|
||||
|
||||
|
||||
/**
|
||||
* Read signals from a pipe in a loop, and reload keys from disk if
|
||||
* SIGUSR1 is read from the pipe.
|
||||
*
|
||||
* @return GNUNET_OK if we terminated normally, GNUNET_SYSERR on error
|
||||
*/
|
||||
int
|
||||
TALER_MINT_key_reload_loop (void);
|
||||
|
||||
|
||||
/**
|
||||
* Handle a "/keys" request
|
||||
*
|
||||
* @param rh context of the handler
|
||||
* @param connection the MHD connection to handle
|
||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||
* @param upload_data upload data
|
||||
* @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TALER_MINT_handler_keys (struct RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
void **connection_cls,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size);
|
||||
|
||||
#endif
|
300
src/mint/taler-mint-httpd_mhd.c
Normal file
300
src/mint/taler-mint-httpd_mhd.c
Normal file
@ -0,0 +1,300 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 GNUnet e.V.
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file taler-mint-httpd_mhd.c
|
||||
* @brief helpers for MHD interaction
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <jansson.h>
|
||||
#include <microhttpd.h>
|
||||
#include <libpq-fe.h>
|
||||
#include <pthread.h>
|
||||
#include "taler_microhttpd_lib.h"
|
||||
#include "taler-mint-httpd.h"
|
||||
#include "taler-mint-httpd_mhd.h"
|
||||
|
||||
|
||||
/**
|
||||
* Function to call to handle the request by sending
|
||||
* back static data from the @a rh.
|
||||
*
|
||||
* @param rh context of the handler
|
||||
* @param connection the MHD connection to handle
|
||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||
* @param upload_data upload data
|
||||
* @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TALER_MINT_handler_static_response (struct RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
void **connection_cls,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size)
|
||||
{
|
||||
struct MHD_Response *response;
|
||||
int ret;
|
||||
|
||||
if (0 == rh->data_size)
|
||||
rh->data_size = strlen ((const char *) rh->data);
|
||||
response = MHD_create_response_from_buffer (rh->data_size,
|
||||
(void *) rh->data,
|
||||
MHD_RESPMEM_PERSISTENT);
|
||||
if (NULL == response)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return MHD_NO;
|
||||
}
|
||||
if (NULL != rh->mime_type)
|
||||
(void) MHD_add_response_header (response,
|
||||
MHD_HTTP_HEADER_CONTENT_TYPE,
|
||||
rh->mime_type);
|
||||
ret = MHD_queue_response (connection,
|
||||
rh->response_code,
|
||||
response);
|
||||
MHD_destroy_response (response);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to call to handle the request by sending
|
||||
* back a redirect to the AGPL source code.
|
||||
*
|
||||
* @param rh context of the handler
|
||||
* @param connection the MHD connection to handle
|
||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||
* @param upload_data upload data
|
||||
* @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TALER_MINT_handler_agpl_redirect (struct RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
void **connection_cls,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size)
|
||||
{
|
||||
const char *agpl =
|
||||
"This server is licensed under the Affero GPL. You will now be redirected to the source code.";
|
||||
struct MHD_Response *response;
|
||||
int ret;
|
||||
|
||||
response = MHD_create_response_from_buffer (strlen (agpl),
|
||||
(void *) agpl,
|
||||
MHD_RESPMEM_PERSISTENT);
|
||||
if (NULL == response)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return MHD_NO;
|
||||
}
|
||||
if (NULL != rh->mime_type)
|
||||
(void) MHD_add_response_header (response,
|
||||
MHD_HTTP_HEADER_CONTENT_TYPE,
|
||||
rh->mime_type);
|
||||
MHD_add_response_header (response,
|
||||
MHD_HTTP_HEADER_LOCATION,
|
||||
"http://www.git.taler.net/?p=mint.git");
|
||||
ret = MHD_queue_response (connection,
|
||||
rh->response_code,
|
||||
response);
|
||||
MHD_destroy_response (response);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to call to handle the request by building a JSON
|
||||
* reply from varargs.
|
||||
*
|
||||
* @param rh context of the handler
|
||||
* @param connection the MHD connection to handle
|
||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||
* @param response_code HTTP response code to use
|
||||
* @param do_cache can the response be cached? (0: no, 1: yes)
|
||||
* @param fmt format string for pack
|
||||
* @param ... varargs
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TALER_MINT_helper_send_json_pack (struct RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
void *connection_cls,
|
||||
int response_code,
|
||||
int do_cache,
|
||||
const char *fmt,
|
||||
...)
|
||||
{
|
||||
int ret;
|
||||
json_t *json;
|
||||
va_list argp;
|
||||
char *json_str;
|
||||
struct MHD_Response *response;
|
||||
|
||||
va_start (argp, fmt);
|
||||
json = json_vpack_ex (NULL, 0, fmt, argp);
|
||||
va_end (argp);
|
||||
if (NULL == json)
|
||||
return MHD_NO;
|
||||
json_str = json_dumps (json, JSON_INDENT(2));
|
||||
json_decref (json);
|
||||
if (NULL == json_str)
|
||||
return MHD_NO;
|
||||
response = MHD_create_response_from_buffer (strlen (json_str),
|
||||
json_str,
|
||||
MHD_RESPMEM_MUST_FREE);
|
||||
if (NULL == response)
|
||||
{
|
||||
free (json_str);
|
||||
return MHD_NO;
|
||||
}
|
||||
if (NULL != rh->mime_type)
|
||||
(void) MHD_add_response_header (response,
|
||||
MHD_HTTP_HEADER_CONTENT_TYPE,
|
||||
rh->mime_type);
|
||||
ret = MHD_queue_response (connection,
|
||||
response_code,
|
||||
response);
|
||||
MHD_destroy_response (response);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function to call to handle the request by building a JSON
|
||||
* reply with an error message from @a rh.
|
||||
*
|
||||
* @param rh context of the handler
|
||||
* @param connection the MHD connection to handle
|
||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||
* @param upload_data upload data
|
||||
* @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TALER_MINT_handler_send_json_pack_error (struct RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
void **connection_cls,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size)
|
||||
{
|
||||
return TALER_MINT_helper_send_json_pack (rh,
|
||||
connection,
|
||||
connection_cls,
|
||||
1, /* caching enabled */
|
||||
rh->response_code,
|
||||
"{s:s}",
|
||||
"error",
|
||||
rh->data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a response for an invalid argument.
|
||||
*
|
||||
* @param connection the MHD connection to use
|
||||
* @param param_name the parameter that is missing
|
||||
* @return a GNUnet result code
|
||||
*/
|
||||
static int
|
||||
request_arg_invalid (struct MHD_Connection *connection,
|
||||
const char *param_name)
|
||||
{
|
||||
json_t *json;
|
||||
json = json_pack ("{ s:s, s:s }",
|
||||
"error", "invalid parameter",
|
||||
"parameter", param_name);
|
||||
if (MHD_YES != send_response_json (connection, json, MHD_HTTP_BAD_REQUEST))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
return GNUNET_NO;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a GET paramater that is a string,
|
||||
* or send an error response if the parameter is missing.
|
||||
*
|
||||
* @param connection the connection to get the parameter from /
|
||||
* send the error response to
|
||||
* @param param_name the parameter name
|
||||
* @param str pointer to store the parameter string,
|
||||
* must be freed by the caller
|
||||
* @return GNUNET_YES if the parameter is present and valid,
|
||||
* GNUNET_NO if the parameter is missing
|
||||
* GNUNET_SYSERR on internal error
|
||||
*/
|
||||
static int
|
||||
request_arg_require_string (struct MHD_Connection *connection,
|
||||
const char *param_name,
|
||||
const char **str)
|
||||
{
|
||||
*str = MHD_lookup_connection_value (connection, MHD_GET_ARGUMENT_KIND, param_name);
|
||||
if (NULL == *str)
|
||||
{
|
||||
if (MHD_NO ==
|
||||
request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST,
|
||||
"{ s:s, s:s }",
|
||||
"error", "missing parameter",
|
||||
"parameter", param_name))
|
||||
return GNUNET_SYSERR;
|
||||
return GNUNET_NO;
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extraxt base32crockford encoded data from request.
|
||||
*
|
||||
* Queues an error response to the connection if the parameter is missing or
|
||||
* invalid.
|
||||
*
|
||||
* @param connection the MHD connection
|
||||
* @param param_name the name of the parameter with the key
|
||||
* @param[out] out_data pointer to store the result
|
||||
* @param out_size expected size of data
|
||||
* @return
|
||||
* GNUNET_YES if the the argument is present
|
||||
* GNUNET_NO if the argument is absent or malformed
|
||||
* GNUNET_SYSERR on internal error (error response could not be sent)
|
||||
*/
|
||||
int
|
||||
TALER_MINT_mhd_request_arg_data (struct MHD_Connection *connection,
|
||||
const char *param_name,
|
||||
void *out_data,
|
||||
size_t out_size)
|
||||
{
|
||||
const char *str;
|
||||
int ret;
|
||||
|
||||
if (GNUNET_OK != (ret = request_arg_require_string (connection, param_name, &str)))
|
||||
return ret;
|
||||
if (GNUNET_OK != GNUNET_STRINGS_string_to_data (str, strlen (str), out_data, out_size))
|
||||
return request_arg_invalid (connection, param_name);
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* end of taler-mint-httpd_mhd.c */
|
132
src/mint/taler-mint-httpd_mhd.h
Normal file
132
src/mint/taler-mint-httpd_mhd.h
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 GNUnet e.V.
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file taler-mint-httpd_mhd.h
|
||||
* @brief helpers for MHD interaction
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef TALER_MINT_HTTPD_MHD_H
|
||||
#define TALER_MINT_HTTPD_MHD_H
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <microhttpd.h>
|
||||
#include "taler-mint-httpd.h"
|
||||
|
||||
|
||||
/**
|
||||
* Function to call to handle the request by sending
|
||||
* back static data from the @a rh.
|
||||
*
|
||||
* @param rh context of the handler
|
||||
* @param connection the MHD connection to handle
|
||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||
* @param upload_data upload data
|
||||
* @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TALER_MINT_handler_static_response (struct RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
void **connection_cls,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size);
|
||||
|
||||
|
||||
/**
|
||||
* Function to call to handle the request by sending
|
||||
* back a redirect to the AGPL source code.
|
||||
*
|
||||
* @param rh context of the handler
|
||||
* @param connection the MHD connection to handle
|
||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||
* @param upload_data upload data
|
||||
* @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TALER_MINT_handler_agpl_redirect (struct RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
void **connection_cls,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size);
|
||||
|
||||
|
||||
/**
|
||||
* Function to call to handle the request by building a JSON
|
||||
* reply from varargs.
|
||||
*
|
||||
* @param rh context of the handler
|
||||
* @param connection the MHD connection to handle
|
||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||
* @param response_code HTTP response code to use
|
||||
* @param do_cache can the response be cached? (0: no, 1: yes)
|
||||
* @param fmt format string for pack
|
||||
* @param ... varargs
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TALER_MINT_helper_send_json_pack (struct RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
void *connection_cls,
|
||||
int response_code,
|
||||
int do_cache,
|
||||
const char *fmt,
|
||||
...);
|
||||
|
||||
|
||||
/**
|
||||
* Function to call to handle the request by building a JSON
|
||||
* reply with an error message from @a rh.
|
||||
*
|
||||
* @param rh context of the handler
|
||||
* @param connection the MHD connection to handle
|
||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||
* @param upload_data upload data
|
||||
* @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TALER_MINT_handler_send_json_pack_error (struct RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
void **connection_cls,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size);
|
||||
|
||||
|
||||
/**
|
||||
* Extraxt base32crockford encoded data from request.
|
||||
*
|
||||
* Queues an error response to the connection if the parameter is missing or
|
||||
* invalid.
|
||||
*
|
||||
* @param connection the MHD connection
|
||||
* @param param_name the name of the parameter with the key
|
||||
* @param[out] out_data pointer to store the result
|
||||
* @param out_size expected size of data
|
||||
* @return
|
||||
* GNUNET_YES if the the argument is present
|
||||
* GNUNET_NO if the argument is absent or malformed
|
||||
* GNUNET_SYSERR on internal error (error response could not be sent)
|
||||
*/
|
||||
int
|
||||
TALER_MINT_mhd_request_arg_data (struct MHD_Connection *connection,
|
||||
const char *param_name,
|
||||
void *out_data,
|
||||
size_t out_size);
|
||||
|
||||
#endif
|
1497
src/mint/taler-mint-httpd_refresh.c
Normal file
1497
src/mint/taler-mint-httpd_refresh.c
Normal file
File diff suppressed because it is too large
Load Diff
103
src/mint/taler-mint-httpd_refresh.h
Normal file
103
src/mint/taler-mint-httpd_refresh.h
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 GNUnet e.V.
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file taler-mint-httpd_refresh.h
|
||||
* @brief Handle /refresh/ requests
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef TALER_MINT_HTTPD_REFRESH_H
|
||||
#define TALER_MINT_HTTPD_REFRESH_H
|
||||
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <microhttpd.h>
|
||||
#include "taler-mint-httpd.h"
|
||||
|
||||
|
||||
/**
|
||||
* Handle a "/refresh/melt" request
|
||||
*
|
||||
* @param rh context of the handler
|
||||
* @param connection the MHD connection to handle
|
||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||
* @param upload_data upload data
|
||||
* @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TALER_MINT_handler_refresh_melt (struct RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
void **connection_cls,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size);
|
||||
|
||||
|
||||
/**
|
||||
* Handle a "/refresh/commit" request
|
||||
*
|
||||
* @param rh context of the handler
|
||||
* @param connection the MHD connection to handle
|
||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||
* @param upload_data upload data
|
||||
* @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TALER_MINT_handler_refresh_commit (struct RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
void **connection_cls,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size);
|
||||
|
||||
|
||||
/**
|
||||
* Handle a "/refresh/link" request
|
||||
*
|
||||
* @param rh context of the handler
|
||||
* @param connection the MHD connection to handle
|
||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||
* @param upload_data upload data
|
||||
* @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TALER_MINT_handler_refresh_link (struct RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
void **connection_cls,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size);
|
||||
|
||||
|
||||
/**
|
||||
* Handle a "/refresh/reveal" request
|
||||
*
|
||||
* @param rh context of the handler
|
||||
* @param connection the MHD connection to handle
|
||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||
* @param upload_data upload data
|
||||
* @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TALER_MINT_handler_refresh_reveal (struct RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
void **connection_cls,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size);
|
||||
|
||||
|
||||
#endif
|
400
src/mint/taler-mint-httpd_withdraw.c
Normal file
400
src/mint/taler-mint-httpd_withdraw.c
Normal file
@ -0,0 +1,400 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 GNUnet e.V.
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file taler-mint-httpd_withdraw.c
|
||||
* @brief Handle /withdraw/ requests
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <jansson.h>
|
||||
#include <microhttpd.h>
|
||||
#include <libpq-fe.h>
|
||||
#include <pthread.h>
|
||||
#include "mint.h"
|
||||
#include "mint_db.h"
|
||||
#include "taler_types.h"
|
||||
#include "taler_signatures.h"
|
||||
#include "taler_rsa.h"
|
||||
#include "taler_json_lib.h"
|
||||
#include "taler_microhttpd_lib.h"
|
||||
#include "taler-mint-httpd_keys.h"
|
||||
#include "taler-mint-httpd_mhd.h"
|
||||
#include "taler-mint-httpd_withdraw.h"
|
||||
|
||||
|
||||
/**
|
||||
* Convert a signature (with purpose) to
|
||||
* a JSON object representation.
|
||||
*
|
||||
* @param purpose purpose of the signature
|
||||
* @param signature the signature
|
||||
* @return the JSON reporesentation of the signature with purpose
|
||||
*/
|
||||
static json_t *
|
||||
sig_to_json (const struct GNUNET_CRYPTO_EccSignaturePurpose *purpose,
|
||||
const struct GNUNET_CRYPTO_EddsaSignature *signature)
|
||||
{
|
||||
json_t *root;
|
||||
json_t *el;
|
||||
|
||||
root = json_object ();
|
||||
|
||||
el = json_integer ((json_int_t) ntohl (purpose->size));
|
||||
json_object_set_new (root, "size", el);
|
||||
|
||||
el = json_integer ((json_int_t) ntohl (purpose->purpose));
|
||||
json_object_set_new (root, "purpose", el);
|
||||
|
||||
el = TALER_JSON_from_data (signature, sizeof (struct GNUNET_CRYPTO_EddsaSignature));
|
||||
json_object_set_new (root, "sig", el);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sign a reserve's status with the current signing key.
|
||||
*
|
||||
* @param reserve the reserve to sign
|
||||
* @param key_state the key state containing the current
|
||||
* signing private key
|
||||
*/
|
||||
static void
|
||||
sign_reserve (struct Reserve *reserve,
|
||||
struct MintKeyState *key_state)
|
||||
{
|
||||
reserve->status_sign_pub = key_state->current_sign_key_issue.signkey_pub;
|
||||
reserve->status_sig_purpose.purpose = htonl (TALER_SIGNATURE_RESERVE_STATUS);
|
||||
reserve->status_sig_purpose.size = htonl (sizeof (struct Reserve) -
|
||||
offsetof (struct Reserve, status_sig_purpose));
|
||||
GNUNET_CRYPTO_eddsa_sign (&key_state->current_sign_key_issue.signkey_priv,
|
||||
&reserve->status_sig_purpose,
|
||||
&reserve->status_sig);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle a "/withdraw/status" request
|
||||
*
|
||||
* @param rh context of the handler
|
||||
* @param connection the MHD connection to handle
|
||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||
* @param upload_data upload data
|
||||
* @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TALER_MINT_handler_withdraw_status (struct RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
void **connection_cls,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size)
|
||||
{
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey reserve_pub;
|
||||
PGconn *db_conn;
|
||||
int res;
|
||||
struct Reserve reserve;
|
||||
struct MintKeyState *key_state;
|
||||
int must_update = GNUNET_NO;
|
||||
json_t *json;
|
||||
|
||||
res = TALER_MINT_mhd_request_arg_data (connection,
|
||||
"reserve_pub",
|
||||
&reserve_pub,
|
||||
sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
|
||||
if (GNUNET_SYSERR == res)
|
||||
{
|
||||
// FIXME: return 'internal error'
|
||||
GNUNET_break (0);
|
||||
return MHD_NO;
|
||||
}
|
||||
if (GNUNET_OK != res)
|
||||
return MHD_YES;
|
||||
if (NULL == (db_conn = TALER_MINT_DB_get_connection ()))
|
||||
{
|
||||
// FIXME: return 'internal error'?
|
||||
GNUNET_break (0);
|
||||
return MHD_NO;
|
||||
}
|
||||
res = TALER_MINT_DB_get_reserve (db_conn,
|
||||
&reserve_pub,
|
||||
&reserve);
|
||||
if (GNUNET_SYSERR == res)
|
||||
return TALER_MINT_helper_send_json_pack (rh,
|
||||
connection,
|
||||
connection_cls,
|
||||
0 /* no caching */,
|
||||
MHD_HTTP_NOT_FOUND,
|
||||
"{s:s}",
|
||||
"error",
|
||||
"Reserve not found");
|
||||
if (GNUNET_OK != res)
|
||||
{
|
||||
// FIXME: return 'internal error'?
|
||||
GNUNET_break (0);
|
||||
return MHD_NO;
|
||||
}
|
||||
key_state = TALER_MINT_key_state_acquire ();
|
||||
if (0 != memcmp (&key_state->current_sign_key_issue.signkey_pub,
|
||||
&reserve.status_sign_pub,
|
||||
sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
|
||||
{
|
||||
sign_reserve (&reserve, key_state);
|
||||
must_update = GNUNET_YES;
|
||||
}
|
||||
if ((GNUNET_YES == must_update) &&
|
||||
(GNUNET_OK != TALER_MINT_DB_update_reserve (db_conn, &reserve, !must_update)))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return MHD_YES;
|
||||
}
|
||||
|
||||
/* Convert the public information of a reserve (i.e.
|
||||
excluding private key) to a JSON object. */
|
||||
json = json_object ();
|
||||
json_object_set_new (json,
|
||||
"balance",
|
||||
TALER_JSON_from_amount (TALER_amount_ntoh (reserve.balance)));
|
||||
json_object_set_new (json,
|
||||
"expiration",
|
||||
TALER_JSON_from_abs (GNUNET_TIME_absolute_ntoh (reserve.expiration)));
|
||||
json_object_set_new (json,
|
||||
"signature",
|
||||
sig_to_json (&reserve.status_sig_purpose,
|
||||
&reserve.status_sig));
|
||||
|
||||
return send_response_json (connection,
|
||||
json,
|
||||
MHD_HTTP_OK);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send positive, normal response for "/withdraw/sign".
|
||||
*
|
||||
* @param connection the connection to send the response to
|
||||
* @param collectable the collectable blindcoin (i.e. the blindly signed coin)
|
||||
* @return a MHD result code
|
||||
*/
|
||||
static int
|
||||
helper_withdraw_sign_send_reply (struct MHD_Connection *connection,
|
||||
const struct CollectableBlindcoin *collectable)
|
||||
{
|
||||
json_t *root = json_object ();
|
||||
|
||||
json_object_set_new (root, "ev_sig",
|
||||
TALER_JSON_from_data (&collectable->ev_sig,
|
||||
sizeof (struct TALER_RSA_Signature)));
|
||||
return send_response_json (connection,
|
||||
root,
|
||||
MHD_HTTP_OK);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle a "/withdraw/sign" request
|
||||
*
|
||||
* @param rh context of the handler
|
||||
* @param connection the MHD connection to handle
|
||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||
* @param upload_data upload data
|
||||
* @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TALER_MINT_handler_withdraw_sign (struct RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
void **connection_cls,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size)
|
||||
{
|
||||
struct TALER_WithdrawRequest wsrd;
|
||||
int res;
|
||||
PGconn *db_conn;
|
||||
struct Reserve reserve;
|
||||
struct MintKeyState *key_state;
|
||||
struct CollectableBlindcoin collectable;
|
||||
struct TALER_MINT_DenomKeyIssue *dki;
|
||||
struct TALER_RSA_Signature ev_sig;
|
||||
struct TALER_Amount amount_required;
|
||||
|
||||
memset (&wsrd,
|
||||
0,
|
||||
sizeof (struct TALER_WithdrawRequest));
|
||||
res = TALER_MINT_mhd_request_arg_data (connection,
|
||||
"reserve_pub",
|
||||
&wsrd.reserve_pub,
|
||||
sizeof (struct GNUNET_CRYPTO_EddsaPublicKey));
|
||||
if (GNUNET_SYSERR == res)
|
||||
{
|
||||
// FIXME: return 'internal error'?
|
||||
GNUNET_break (0);
|
||||
return MHD_NO;
|
||||
}
|
||||
if (GNUNET_OK != res)
|
||||
return MHD_YES;
|
||||
res = TALER_MINT_mhd_request_arg_data (connection,
|
||||
"denom_pub",
|
||||
&wsrd.denomination_pub,
|
||||
sizeof (struct TALER_RSA_PublicKeyBinaryEncoded));
|
||||
if (GNUNET_SYSERR == res)
|
||||
{
|
||||
// FIXME: return 'internal error'?
|
||||
GNUNET_break (0);
|
||||
return MHD_NO;
|
||||
}
|
||||
if (GNUNET_OK != res)
|
||||
return MHD_YES;
|
||||
res = TALER_MINT_mhd_request_arg_data (connection,
|
||||
"coin_ev",
|
||||
&wsrd.coin_envelope,
|
||||
sizeof (struct TALER_RSA_Signature));
|
||||
if (GNUNET_SYSERR == res)
|
||||
{
|
||||
// FIXME: return 'internal error'?
|
||||
GNUNET_break (0);
|
||||
return MHD_NO;
|
||||
}
|
||||
if (GNUNET_OK != res)
|
||||
return MHD_YES;
|
||||
res = TALER_MINT_mhd_request_arg_data (connection,
|
||||
"reserve_sig",
|
||||
&wsrd.sig,
|
||||
sizeof (struct GNUNET_CRYPTO_EddsaSignature));
|
||||
if (GNUNET_SYSERR == res)
|
||||
{
|
||||
// FIXME: return 'internal error'?
|
||||
GNUNET_break (0);
|
||||
return MHD_NO;
|
||||
}
|
||||
if (GNUNET_OK != res)
|
||||
return MHD_YES;
|
||||
|
||||
if (NULL == (db_conn = TALER_MINT_DB_get_connection ()))
|
||||
{
|
||||
// FIXME: return 'internal error'?
|
||||
GNUNET_break (0);
|
||||
return MHD_NO;
|
||||
}
|
||||
|
||||
res = TALER_MINT_DB_get_collectable_blindcoin (db_conn,
|
||||
&wsrd.coin_envelope,
|
||||
&collectable);
|
||||
if (GNUNET_SYSERR == res)
|
||||
{
|
||||
// FIXME: return 'internal error'
|
||||
GNUNET_break (0);
|
||||
return MHD_NO;
|
||||
}
|
||||
|
||||
/* Don't sign again if we have already signed the coin */
|
||||
if (GNUNET_YES == res)
|
||||
return helper_withdraw_sign_send_reply (connection,
|
||||
&collectable);
|
||||
GNUNET_assert (GNUNET_NO == res);
|
||||
res = TALER_MINT_DB_get_reserve (db_conn,
|
||||
&wsrd.reserve_pub,
|
||||
&reserve);
|
||||
if (GNUNET_SYSERR == res)
|
||||
{
|
||||
// FIXME: return 'internal error'
|
||||
GNUNET_break (0);
|
||||
return MHD_NO;
|
||||
}
|
||||
if (GNUNET_NO == res)
|
||||
return request_send_json_pack (connection,
|
||||
MHD_HTTP_NOT_FOUND,
|
||||
"{s:s}",
|
||||
"error", "Reserve not found");
|
||||
|
||||
// fill out all the missing info in the request before
|
||||
// we can check the signature on the request
|
||||
|
||||
wsrd.purpose.purpose = htonl (TALER_SIGNATURE_WITHDRAW);
|
||||
wsrd.purpose.size = htonl (sizeof (struct TALER_WithdrawRequest) -
|
||||
offsetof (struct TALER_WithdrawRequest, purpose));
|
||||
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_WITHDRAW,
|
||||
&wsrd.purpose,
|
||||
&wsrd.sig,
|
||||
&wsrd.reserve_pub))
|
||||
return request_send_json_pack (connection,
|
||||
MHD_HTTP_UNAUTHORIZED,
|
||||
"{s:s}",
|
||||
"error", "Invalid Signature");
|
||||
|
||||
key_state = TALER_MINT_key_state_acquire ();
|
||||
dki = TALER_MINT_get_denom_key (key_state,
|
||||
&wsrd.denomination_pub);
|
||||
TALER_MINT_key_state_release (key_state);
|
||||
if (NULL == dki)
|
||||
return request_send_json_pack (connection, MHD_HTTP_NOT_FOUND,
|
||||
"{s:s}",
|
||||
"error", "Denomination not found");
|
||||
|
||||
amount_required = TALER_amount_ntoh (dki->value);
|
||||
amount_required = TALER_amount_add (amount_required,
|
||||
TALER_amount_ntoh (dki->fee_withdraw));
|
||||
|
||||
if (0 < TALER_amount_cmp (amount_required,
|
||||
TALER_amount_ntoh (reserve.balance)))
|
||||
return request_send_json_pack (connection,
|
||||
MHD_HTTP_PAYMENT_REQUIRED,
|
||||
"{s:s}",
|
||||
"error", "Insufficient funds");
|
||||
if (GNUNET_OK != TALER_RSA_sign (dki->denom_priv,
|
||||
&wsrd.coin_envelope,
|
||||
sizeof (struct TALER_RSA_BlindedSignaturePurpose),
|
||||
&ev_sig))
|
||||
{
|
||||
// FIXME: return 'internal error'
|
||||
GNUNET_break (0);
|
||||
return MHD_NO;
|
||||
}
|
||||
|
||||
reserve.balance = TALER_amount_hton (TALER_amount_subtract (TALER_amount_ntoh (reserve.balance),
|
||||
amount_required));
|
||||
if (GNUNET_OK !=
|
||||
TALER_MINT_DB_update_reserve (db_conn,
|
||||
&reserve,
|
||||
GNUNET_YES))
|
||||
{
|
||||
// FIXME: return 'internal error'
|
||||
GNUNET_break (0);
|
||||
return MHD_NO;
|
||||
}
|
||||
|
||||
collectable.ev = wsrd.coin_envelope;
|
||||
collectable.ev_sig = ev_sig;
|
||||
collectable.reserve_pub = wsrd.reserve_pub;
|
||||
collectable.reserve_sig = wsrd.sig;
|
||||
if (GNUNET_OK !=
|
||||
TALER_MINT_DB_insert_collectable_blindcoin (db_conn,
|
||||
&collectable))
|
||||
{
|
||||
// FIXME: return 'internal error'
|
||||
GNUNET_break (0);
|
||||
return GNUNET_NO;;
|
||||
}
|
||||
return helper_withdraw_sign_send_reply (connection,
|
||||
&collectable);
|
||||
}
|
||||
|
||||
/* end of taler-mint-httpd_withdraw.c */
|
65
src/mint/taler-mint-httpd_withdraw.h
Normal file
65
src/mint/taler-mint-httpd_withdraw.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 GNUnet e.V.
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
/**
|
||||
* @file taler-mint-httpd_withdraw.h
|
||||
* @brief Handle /withdraw/ requests
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#ifndef TALER_MINT_HTTPD_WITHDRAW_H
|
||||
#define TALER_MINT_HTTPD_WITHDRAW_H
|
||||
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <microhttpd.h>
|
||||
#include "taler-mint-httpd.h"
|
||||
|
||||
/**
|
||||
* Handle a "/withdraw/status" request
|
||||
*
|
||||
* @param rh context of the handler
|
||||
* @param connection the MHD connection to handle
|
||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||
* @param upload_data upload data
|
||||
* @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TALER_MINT_handler_withdraw_status (struct RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
void **connection_cls,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size);
|
||||
|
||||
|
||||
/**
|
||||
* Handle a "/withdraw/sign" request
|
||||
*
|
||||
* @param rh context of the handler
|
||||
* @param connection the MHD connection to handle
|
||||
* @param[IN|OUT] connection_cls the connection's closure (can be updated)
|
||||
* @param upload_data upload data
|
||||
* @param[IN|OUT] upload_data_size number of bytes (left) in @a upload_data
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
TALER_MINT_handler_withdraw_sign (struct RequestHandler *rh,
|
||||
struct MHD_Connection *connection,
|
||||
void **connection_cls,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size);
|
||||
|
||||
#endif
|
169
src/mint/taler-mint-keycheck.c
Normal file
169
src/mint/taler-mint-keycheck.c
Normal file
@ -0,0 +1,169 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file taler-mint-keycheck.c
|
||||
* @brief Check mint keys for validity.
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
*/
|
||||
|
||||
#include <platform.h>
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include "mint.h"
|
||||
#include "taler_signatures.h"
|
||||
|
||||
|
||||
static char *mintdir;
|
||||
static struct GNUNET_CONFIGURATION_Handle *kcfg;
|
||||
|
||||
|
||||
static int
|
||||
signkeys_iter (void *cls, const struct TALER_MINT_SignKeyIssue *ski)
|
||||
{
|
||||
struct GNUNET_TIME_Absolute start;
|
||||
|
||||
printf ("iterating over key for start time %s\n",
|
||||
GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (ski->start)));
|
||||
|
||||
start = GNUNET_TIME_absolute_ntoh (ski->start);
|
||||
|
||||
if (ntohl (ski->purpose.size) !=
|
||||
(sizeof (struct TALER_MINT_SignKeyIssue) - offsetof (struct TALER_MINT_SignKeyIssue, purpose)))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Signkey with start %s has invalid purpose field (timestamp: %llu)\n",
|
||||
GNUNET_STRINGS_absolute_time_to_string (start),
|
||||
(long long) start.abs_value_us);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
|
||||
if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_SIGNKEY,
|
||||
&ski->purpose,
|
||||
&ski->signature,
|
||||
&ski->master_pub))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Signkey with start %s has invalid signature (timestamp: %llu)\n",
|
||||
GNUNET_STRINGS_absolute_time_to_string (start),
|
||||
(long long) start.abs_value_us);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
printf ("key valid\n");
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
mint_signkeys_check ()
|
||||
{
|
||||
if (0 > TALER_MINT_signkeys_iterate (mintdir, signkeys_iter, NULL))
|
||||
return GNUNET_NO;
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
static int denomkeys_iter (void *cls,
|
||||
const char *alias,
|
||||
const struct TALER_MINT_DenomKeyIssue *dki)
|
||||
{
|
||||
struct GNUNET_TIME_Absolute start;
|
||||
|
||||
start = GNUNET_TIME_absolute_ntoh (dki->start);
|
||||
|
||||
if (ntohl (dki->purpose.size) !=
|
||||
(sizeof (struct TALER_MINT_DenomKeyIssue) - offsetof (struct TALER_MINT_DenomKeyIssue, purpose)))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Denomkey for '%s' with start %s has invalid purpose field (timestamp: %llu)\n",
|
||||
alias,
|
||||
GNUNET_STRINGS_absolute_time_to_string (start),
|
||||
(long long) start.abs_value_us);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
if (GNUNET_OK != GNUNET_CRYPTO_eddsa_verify (TALER_SIGNATURE_MASTER_DENOM,
|
||||
&dki->purpose,
|
||||
&dki->signature,
|
||||
&dki->master))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Denomkey for '%s'with start %s has invalid signature (timestamp: %llu)\n",
|
||||
alias,
|
||||
GNUNET_STRINGS_absolute_time_to_string (start),
|
||||
(long long) start.abs_value_us);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
printf ("denom key valid\n");
|
||||
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
mint_denomkeys_check ()
|
||||
{
|
||||
if (0 > TALER_MINT_denomkeys_iterate (mintdir, denomkeys_iter, NULL))
|
||||
return GNUNET_NO;
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
mint_keys_check (void)
|
||||
{
|
||||
if (GNUNET_OK != mint_signkeys_check ())
|
||||
return GNUNET_NO;
|
||||
return mint_denomkeys_check ();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The main function of the keyup tool
|
||||
*
|
||||
* @param argc number of arguments from the command line
|
||||
* @param argv command line arguments
|
||||
* @return 0 ok, 1 on error
|
||||
*/
|
||||
int
|
||||
main (int argc, char *const *argv)
|
||||
{
|
||||
static const struct GNUNET_GETOPT_CommandLineOption options[] = {
|
||||
GNUNET_GETOPT_OPTION_HELP ("gnunet-mint-keyup OPTIONS"),
|
||||
{'d', "mint-dir", "DIR",
|
||||
"mint directory with keys to update", 1,
|
||||
&GNUNET_GETOPT_set_filename, &mintdir},
|
||||
GNUNET_GETOPT_OPTION_END
|
||||
};
|
||||
|
||||
GNUNET_assert (GNUNET_OK == GNUNET_log_setup ("taler-mint-keycheck", "WARNING", NULL));
|
||||
|
||||
if (GNUNET_GETOPT_run ("taler-mint-keyup", options, argc, argv) < 0)
|
||||
return 1;
|
||||
if (NULL == mintdir)
|
||||
{
|
||||
fprintf (stderr, "mint directory not given\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
kcfg = TALER_MINT_config_load (mintdir);
|
||||
if (NULL == kcfg)
|
||||
{
|
||||
fprintf (stderr, "can't load mint configuration\n");
|
||||
return 1;
|
||||
}
|
||||
if (GNUNET_OK != mint_keys_check ())
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
657
src/mint/taler-mint-keyup.c
Normal file
657
src/mint/taler-mint-keyup.c
Normal file
@ -0,0 +1,657 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file taler-mint-keyup.c
|
||||
* @brief Update the mint's keys for coins and signatures,
|
||||
* using the mint's offline master key.
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
*/
|
||||
|
||||
#include <platform.h>
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include "taler_util.h"
|
||||
#include "taler_signatures.h"
|
||||
#include "mint.h"
|
||||
|
||||
#define HASH_CUTOFF 20
|
||||
|
||||
/**
|
||||
* Macro to round microseconds to seconds in GNUNET_TIME_* structs.
|
||||
*/
|
||||
#define ROUND_TO_SECS(name,us_field) name.us_field -= name.us_field % (1000 * 1000);
|
||||
|
||||
|
||||
GNUNET_NETWORK_STRUCT_BEGIN
|
||||
|
||||
struct CoinTypeNBO
|
||||
{
|
||||
struct GNUNET_TIME_RelativeNBO duration_spend;
|
||||
struct GNUNET_TIME_RelativeNBO duration_withdraw;
|
||||
struct TALER_AmountNBO value;
|
||||
struct TALER_AmountNBO fee_withdraw;
|
||||
struct TALER_AmountNBO fee_deposit;
|
||||
struct TALER_AmountNBO fee_refresh;
|
||||
};
|
||||
|
||||
GNUNET_NETWORK_STRUCT_END
|
||||
|
||||
struct CoinTypeParams
|
||||
{
|
||||
struct GNUNET_TIME_Relative duration_spend;
|
||||
struct GNUNET_TIME_Relative duration_withdraw;
|
||||
struct GNUNET_TIME_Relative duration_overlap;
|
||||
struct TALER_Amount value;
|
||||
struct TALER_Amount fee_withdraw;
|
||||
struct TALER_Amount fee_deposit;
|
||||
struct TALER_Amount fee_refresh;
|
||||
struct GNUNET_TIME_Absolute anchor;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Filename of the master private key.
|
||||
*/
|
||||
static char *masterkeyfile;
|
||||
|
||||
/**
|
||||
* Director of the mint, containing the keys.
|
||||
*/
|
||||
static char *mintdir;
|
||||
|
||||
/**
|
||||
* Time to pretend when the key update is executed.
|
||||
*/
|
||||
static char *pretend_time_str;
|
||||
|
||||
/**
|
||||
* Handle to the mint's configuration
|
||||
*/
|
||||
static struct GNUNET_CONFIGURATION_Handle *kcfg;
|
||||
|
||||
/**
|
||||
* Time when the key update is executed. Either the actual current time, or a
|
||||
* pretended time.
|
||||
*/
|
||||
static struct GNUNET_TIME_Absolute now;
|
||||
|
||||
/**
|
||||
* Master private key of the mint.
|
||||
*/
|
||||
static struct GNUNET_CRYPTO_EddsaPrivateKey *master_priv;
|
||||
|
||||
/**
|
||||
* Master public key of the mint.
|
||||
*/
|
||||
static struct GNUNET_CRYPTO_EddsaPublicKey *master_pub;
|
||||
|
||||
/**
|
||||
* Until what time do we provide keys?
|
||||
*/
|
||||
static struct GNUNET_TIME_Absolute lookahead_sign_stamp;
|
||||
|
||||
|
||||
int
|
||||
config_get_denom (const char *section, const char *option, struct TALER_Amount *denom)
|
||||
{
|
||||
char *str;
|
||||
if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (kcfg, section, option, &str))
|
||||
return GNUNET_NO;
|
||||
if (GNUNET_OK != TALER_string_to_amount (str, denom))
|
||||
return GNUNET_SYSERR;
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
get_signkey_dir ()
|
||||
{
|
||||
char *dir;
|
||||
size_t len;
|
||||
len = GNUNET_asprintf (&dir, ("%s" DIR_SEPARATOR_STR DIR_SIGNKEYS), mintdir);
|
||||
GNUNET_assert (len > 0);
|
||||
return dir;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
get_signkey_file (struct GNUNET_TIME_Absolute start)
|
||||
{
|
||||
char *dir;
|
||||
size_t len;
|
||||
len = GNUNET_asprintf (&dir, ("%s" DIR_SEPARATOR_STR DIR_SIGNKEYS DIR_SEPARATOR_STR "%llu"),
|
||||
mintdir, (long long) start.abs_value_us);
|
||||
GNUNET_assert (len > 0);
|
||||
return dir;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Hash the data defining the coin type.
|
||||
* Exclude information that may not be the same for all
|
||||
* instances of the coin type (i.e. the anchor, overlap).
|
||||
*/
|
||||
void
|
||||
hash_coin_type (const struct CoinTypeParams *p, struct GNUNET_HashCode *hash)
|
||||
{
|
||||
struct CoinTypeNBO p_nbo;
|
||||
|
||||
memset (&p_nbo, 0, sizeof (struct CoinTypeNBO));
|
||||
|
||||
p_nbo.duration_spend = GNUNET_TIME_relative_hton (p->duration_spend);
|
||||
p_nbo.duration_withdraw = GNUNET_TIME_relative_hton (p->duration_withdraw);
|
||||
p_nbo.value = TALER_amount_hton (p->value);
|
||||
p_nbo.fee_withdraw = TALER_amount_hton (p->fee_withdraw);
|
||||
p_nbo.fee_deposit = TALER_amount_hton (p->fee_deposit);
|
||||
p_nbo.fee_refresh = TALER_amount_hton (p->fee_refresh);
|
||||
|
||||
GNUNET_CRYPTO_hash (&p_nbo, sizeof (struct CoinTypeNBO), hash);
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
get_cointype_dir (const struct CoinTypeParams *p)
|
||||
{
|
||||
static char dir[4096];
|
||||
size_t len;
|
||||
struct GNUNET_HashCode hash;
|
||||
char *hash_str;
|
||||
char *val_str;
|
||||
unsigned int i;
|
||||
|
||||
hash_coin_type (p, &hash);
|
||||
hash_str = TALER_data_to_string_alloc (&hash, sizeof (struct GNUNET_HashCode));
|
||||
GNUNET_assert (HASH_CUTOFF <= strlen (hash_str) + 1);
|
||||
GNUNET_assert (NULL != hash_str);
|
||||
hash_str[HASH_CUTOFF] = 0;
|
||||
|
||||
val_str = TALER_amount_to_string (p->value);
|
||||
for (i = 0; i < strlen (val_str); i++)
|
||||
if (':' == val_str[i] || '.' == val_str[i])
|
||||
val_str[i] = '_';
|
||||
|
||||
len = GNUNET_snprintf (dir, sizeof (dir),
|
||||
("%s" DIR_SEPARATOR_STR DIR_DENOMKEYS DIR_SEPARATOR_STR "%s-%s"),
|
||||
mintdir, val_str, hash_str);
|
||||
GNUNET_assert (len > 0);
|
||||
GNUNET_free (hash_str);
|
||||
return dir;
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
get_cointype_file (struct CoinTypeParams *p,
|
||||
struct GNUNET_TIME_Absolute start)
|
||||
{
|
||||
const char *dir;
|
||||
static char filename[4096];
|
||||
size_t len;
|
||||
dir = get_cointype_dir (p);
|
||||
len = GNUNET_snprintf (filename, sizeof (filename), ("%s" DIR_SEPARATOR_STR "%llu"),
|
||||
dir, (unsigned long long) start.abs_value_us);
|
||||
GNUNET_assert (len > 0);
|
||||
return filename;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the latest key file from the past.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param filename complete filename (absolute path)
|
||||
* @return #GNUNET_OK to continue to iterate,
|
||||
* #GNUNET_NO to stop iteration with no error,
|
||||
* #GNUNET_SYSERR to abort iteration with error!
|
||||
*/
|
||||
static int
|
||||
get_anchor_iter (void *cls,
|
||||
const char *filename)
|
||||
{
|
||||
struct GNUNET_TIME_Absolute stamp;
|
||||
struct GNUNET_TIME_Absolute *anchor = cls;
|
||||
const char *base;
|
||||
char *end = NULL;
|
||||
|
||||
base = GNUNET_STRINGS_get_short_name (filename);
|
||||
stamp.abs_value_us = strtol (base, &end, 10);
|
||||
|
||||
if ((NULL == end) || (0 != *end))
|
||||
{
|
||||
fprintf(stderr, "Ignoring unexpected file '%s'.\n", filename);
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
// TODO: check if it's actually a valid key file
|
||||
|
||||
if ((stamp.abs_value_us <= now.abs_value_us) && (stamp.abs_value_us > anchor->abs_value_us))
|
||||
*anchor = stamp;
|
||||
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the timestamp where the first new key should be generated.
|
||||
* Relies on correctly named key files.
|
||||
*
|
||||
* @param dir directory with the signed stuff
|
||||
* @param duration how long is one key valid?
|
||||
* @param overlap what's the overlap between the keys validity period?
|
||||
* @param[out] anchor the timestamp where the first new key should be generated
|
||||
*/
|
||||
void
|
||||
get_anchor (const char *dir,
|
||||
struct GNUNET_TIME_Relative duration,
|
||||
struct GNUNET_TIME_Relative overlap,
|
||||
struct GNUNET_TIME_Absolute *anchor)
|
||||
{
|
||||
GNUNET_assert (0 == duration.rel_value_us % 1000000);
|
||||
GNUNET_assert (0 == overlap.rel_value_us % 1000000);
|
||||
if (GNUNET_YES != GNUNET_DISK_directory_test (dir, GNUNET_YES))
|
||||
{
|
||||
*anchor = now;
|
||||
printf ("Can't look for anchor (%s)\n", dir);
|
||||
return;
|
||||
}
|
||||
|
||||
*anchor = GNUNET_TIME_UNIT_ZERO_ABS;
|
||||
if (-1 == GNUNET_DISK_directory_scan (dir, &get_anchor_iter, anchor))
|
||||
{
|
||||
*anchor = now;
|
||||
return;
|
||||
}
|
||||
|
||||
if ((GNUNET_TIME_absolute_add (*anchor, duration)).abs_value_us < now.abs_value_us)
|
||||
{
|
||||
// there's no good anchor, start from now
|
||||
// (existing keys are too old)
|
||||
*anchor = now;
|
||||
}
|
||||
else if (anchor->abs_value_us != now.abs_value_us)
|
||||
{
|
||||
// we have a good anchor
|
||||
*anchor = GNUNET_TIME_absolute_add (*anchor, duration);
|
||||
*anchor = GNUNET_TIME_absolute_subtract (*anchor, overlap);
|
||||
}
|
||||
// anchor is now the stamp where we need to create a new key
|
||||
}
|
||||
|
||||
static void
|
||||
create_signkey_issue (struct GNUNET_TIME_Absolute start,
|
||||
struct GNUNET_TIME_Relative duration,
|
||||
struct TALER_MINT_SignKeyIssue *issue)
|
||||
{
|
||||
struct GNUNET_CRYPTO_EddsaPrivateKey *priv;
|
||||
|
||||
priv = GNUNET_CRYPTO_eddsa_key_create ();
|
||||
GNUNET_assert (NULL != priv);
|
||||
issue->signkey_priv = *priv;
|
||||
GNUNET_free (priv);
|
||||
issue->master_pub = *master_pub;
|
||||
issue->start = GNUNET_TIME_absolute_hton (start);
|
||||
issue->expire = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (start, duration));
|
||||
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (&issue->signkey_priv, &issue->signkey_pub);
|
||||
|
||||
issue->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_SIGNKEY);
|
||||
issue->purpose.size = htonl (sizeof (struct TALER_MINT_SignKeyIssue) - offsetof (struct TALER_MINT_SignKeyIssue, purpose));
|
||||
|
||||
if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign (master_priv, &issue->purpose, &issue->signature))
|
||||
{
|
||||
GNUNET_abort ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
check_signkey_valid (const char *signkey_filename)
|
||||
{
|
||||
// FIXME: do real checks
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
mint_keys_update_signkeys ()
|
||||
{
|
||||
struct GNUNET_TIME_Relative signkey_duration;
|
||||
struct GNUNET_TIME_Absolute anchor;
|
||||
char *signkey_dir;
|
||||
|
||||
if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (kcfg, "mint_keys", "signkey_duration", &signkey_duration))
|
||||
{
|
||||
fprintf (stderr, "Can't read config value mint_keys.signkey_duration\n");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
ROUND_TO_SECS (signkey_duration, rel_value_us);
|
||||
signkey_dir = get_signkey_dir ();
|
||||
// make sure the directory exists
|
||||
if (GNUNET_OK != GNUNET_DISK_directory_create (signkey_dir))
|
||||
{
|
||||
fprintf (stderr, "Cant create signkey dir\n");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
get_anchor (signkey_dir, signkey_duration, GNUNET_TIME_UNIT_ZERO, &anchor);
|
||||
|
||||
while (anchor.abs_value_us < lookahead_sign_stamp.abs_value_us) {
|
||||
char *skf;
|
||||
skf = get_signkey_file (anchor);
|
||||
if (GNUNET_YES != GNUNET_DISK_file_test (skf))
|
||||
{
|
||||
struct TALER_MINT_SignKeyIssue signkey_issue;
|
||||
ssize_t nwrite;
|
||||
printf ("Generating signing key for %s.\n", GNUNET_STRINGS_absolute_time_to_string (anchor));
|
||||
create_signkey_issue (anchor, signkey_duration, &signkey_issue);
|
||||
nwrite = GNUNET_DISK_fn_write (skf, &signkey_issue, sizeof (struct TALER_MINT_SignKeyIssue),
|
||||
(GNUNET_DISK_PERM_USER_WRITE | GNUNET_DISK_PERM_USER_READ));
|
||||
if (nwrite != sizeof (struct TALER_MINT_SignKeyIssue))
|
||||
{
|
||||
fprintf (stderr, "Can't write to file '%s'\n", skf);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
}
|
||||
else if (GNUNET_OK != check_signkey_valid (skf))
|
||||
{
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
anchor = GNUNET_TIME_absolute_add (anchor, signkey_duration);
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
get_cointype_params (const char *ct, struct CoinTypeParams *params)
|
||||
{
|
||||
const char *dir;
|
||||
if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (kcfg, "mint_denom_duration_withdraw", ct, ¶ms->duration_withdraw))
|
||||
{
|
||||
fprintf (stderr, "Withdraw duration not given for coin type '%s'\n", ct);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
ROUND_TO_SECS (params->duration_withdraw, rel_value_us);
|
||||
if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (kcfg, "mint_denom_duration_spend", ct, ¶ms->duration_spend))
|
||||
{
|
||||
fprintf (stderr, "Spend duration not given for coin type '%s'\n", ct);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
ROUND_TO_SECS (params->duration_spend, rel_value_us);
|
||||
if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (kcfg, "mint_denom_duration_overlap", ct, ¶ms->duration_overlap))
|
||||
{
|
||||
fprintf (stderr, "Overlap duration not given for coin type '%s'\n", ct);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
ROUND_TO_SECS (params->duration_overlap, rel_value_us);
|
||||
|
||||
if (GNUNET_OK != config_get_denom ("mint_denom_value", ct, ¶ms->value))
|
||||
{
|
||||
fprintf (stderr, "Value not given for coin type '%s'\n", ct);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
if (GNUNET_OK != config_get_denom ("mint_denom_fee_withdraw", ct, ¶ms->fee_withdraw))
|
||||
{
|
||||
fprintf (stderr, "Withdraw fee not given for coin type '%s'\n", ct);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
if (GNUNET_OK != config_get_denom ("mint_denom_fee_deposit", ct, ¶ms->fee_deposit))
|
||||
{
|
||||
fprintf (stderr, "Deposit fee not given for coin type '%s'\n", ct);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
if (GNUNET_OK != config_get_denom ("mint_denom_fee_refresh", ct, ¶ms->fee_refresh))
|
||||
{
|
||||
fprintf (stderr, "Deposit fee not given for coin type '%s'\n", ct);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
dir = get_cointype_dir (params);
|
||||
get_anchor (dir, params->duration_spend, params->duration_overlap, ¶ms->anchor);
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
create_denomkey_issue (struct CoinTypeParams *params, struct TALER_MINT_DenomKeyIssue *dki)
|
||||
{
|
||||
GNUNET_assert (NULL != (dki->denom_priv = TALER_RSA_key_create ()));
|
||||
TALER_RSA_key_get_public (dki->denom_priv, &dki->denom_pub);
|
||||
dki->master = *master_pub;
|
||||
dki->start = GNUNET_TIME_absolute_hton (params->anchor);
|
||||
dki->expire_withdraw =
|
||||
GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor,
|
||||
params->duration_withdraw));
|
||||
dki->expire_spend =
|
||||
GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add (params->anchor,
|
||||
params->duration_spend));
|
||||
dki->value = TALER_amount_hton (params->value);
|
||||
dki->fee_withdraw = TALER_amount_hton (params->fee_withdraw);
|
||||
dki->fee_deposit = TALER_amount_hton (params->fee_deposit);
|
||||
dki->fee_refresh = TALER_amount_hton (params->fee_refresh);
|
||||
|
||||
dki->purpose.purpose = htonl (TALER_SIGNATURE_MASTER_DENOM);
|
||||
dki->purpose.size = htonl (sizeof (struct TALER_MINT_DenomKeyIssue) - offsetof (struct TALER_MINT_DenomKeyIssue, purpose));
|
||||
|
||||
if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign (master_priv, &dki->purpose, &dki->signature))
|
||||
{
|
||||
GNUNET_abort ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
check_cointype_valid (const char *filename, struct CoinTypeParams *params)
|
||||
{
|
||||
// FIXME: add real checks
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
mint_keys_update_cointype (const char *coin_alias)
|
||||
{
|
||||
struct CoinTypeParams p;
|
||||
const char *cointype_dir;
|
||||
|
||||
if (GNUNET_OK != get_cointype_params (coin_alias, &p))
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
cointype_dir = get_cointype_dir (&p);
|
||||
if (GNUNET_OK != GNUNET_DISK_directory_create (cointype_dir))
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
while (p.anchor.abs_value_us < lookahead_sign_stamp.abs_value_us) {
|
||||
const char *dkf;
|
||||
dkf = get_cointype_file (&p, p.anchor);
|
||||
|
||||
if (GNUNET_YES != GNUNET_DISK_file_test (dkf))
|
||||
{
|
||||
struct TALER_MINT_DenomKeyIssue denomkey_issue;
|
||||
int ret;
|
||||
printf ("Generating denomination key for type '%s', start %s.\n",
|
||||
coin_alias, GNUNET_STRINGS_absolute_time_to_string (p.anchor));
|
||||
printf ("Target path: %s\n", dkf);
|
||||
create_denomkey_issue (&p, &denomkey_issue);
|
||||
ret = TALER_MINT_write_denom_key (dkf, &denomkey_issue);
|
||||
TALER_RSA_key_free (denomkey_issue.denom_priv);
|
||||
if (GNUNET_OK != ret)
|
||||
{
|
||||
fprintf (stderr, "Can't write to file '%s'\n", dkf);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
}
|
||||
else if (GNUNET_OK != check_cointype_valid (dkf, &p))
|
||||
{
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
p.anchor = GNUNET_TIME_absolute_add (p.anchor, p.duration_spend);
|
||||
p.anchor = GNUNET_TIME_absolute_subtract (p.anchor, p.duration_overlap);
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
mint_keys_update_denomkeys ()
|
||||
{
|
||||
char *coin_types;
|
||||
char *ct;
|
||||
char *tok_ctx;
|
||||
|
||||
if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (kcfg, "mint_keys", "coin_types", &coin_types))
|
||||
{
|
||||
fprintf (stderr, "mint_keys.coin_types not in configuration\n");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
for (ct = strtok_r (coin_types, " ", &tok_ctx);
|
||||
ct != NULL;
|
||||
ct = strtok_r (NULL, " ", &tok_ctx))
|
||||
{
|
||||
if (GNUNET_OK != mint_keys_update_cointype (ct))
|
||||
{
|
||||
GNUNET_free (coin_types);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
}
|
||||
GNUNET_free (coin_types);
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
mint_keys_update ()
|
||||
{
|
||||
int ret;
|
||||
struct GNUNET_TIME_Relative lookahead_sign;
|
||||
if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (kcfg, "mint_keys", "lookahead_sign", &lookahead_sign))
|
||||
{
|
||||
fprintf (stderr, "mint_keys.lookahead_sign not found\n");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (lookahead_sign.rel_value_us == 0)
|
||||
{
|
||||
fprintf (stderr, "mint_keys.lookahead_sign must not be zero\n");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
ROUND_TO_SECS (lookahead_sign, rel_value_us);
|
||||
lookahead_sign_stamp = GNUNET_TIME_absolute_add (now, lookahead_sign);
|
||||
|
||||
ret = mint_keys_update_signkeys ();
|
||||
if (GNUNET_OK != ret)
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
return mint_keys_update_denomkeys ();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The main function of the keyup tool
|
||||
*
|
||||
* @param argc number of arguments from the command line
|
||||
* @param argv command line arguments
|
||||
* @return 0 ok, 1 on error
|
||||
*/
|
||||
int
|
||||
main (int argc, char *const *argv)
|
||||
{
|
||||
static const struct GNUNET_GETOPT_CommandLineOption options[] = {
|
||||
GNUNET_GETOPT_OPTION_HELP ("gnunet-mint-keyup OPTIONS"),
|
||||
{'m', "master-key", "FILE",
|
||||
"master key file (private key)", 1,
|
||||
&GNUNET_GETOPT_set_filename, &masterkeyfile},
|
||||
{'d', "mint-dir", "DIR",
|
||||
"mint directory with keys to update", 1,
|
||||
&GNUNET_GETOPT_set_filename, &mintdir},
|
||||
{'t', "time", "TIMESTAMP",
|
||||
"pretend it is a different time for the update", 0,
|
||||
&GNUNET_GETOPT_set_string, &pretend_time_str},
|
||||
GNUNET_GETOPT_OPTION_END
|
||||
};
|
||||
|
||||
GNUNET_assert (GNUNET_OK == GNUNET_log_setup ("taler-mint-keyup", "WARNING", NULL));
|
||||
|
||||
if (GNUNET_GETOPT_run ("taler-mint-keyup", options, argc, argv) < 0)
|
||||
return 1;
|
||||
if (NULL == mintdir)
|
||||
{
|
||||
fprintf (stderr, "mint directory not given\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (NULL != pretend_time_str)
|
||||
{
|
||||
if (GNUNET_OK != GNUNET_STRINGS_fancy_time_to_absolute (pretend_time_str, &now))
|
||||
{
|
||||
fprintf (stderr, "timestamp invalid\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
now = GNUNET_TIME_absolute_get ();
|
||||
}
|
||||
ROUND_TO_SECS (now, abs_value_us);
|
||||
|
||||
kcfg = TALER_MINT_config_load (mintdir);
|
||||
if (NULL == kcfg)
|
||||
{
|
||||
fprintf (stderr, "can't load mint configuration\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (NULL == masterkeyfile)
|
||||
{
|
||||
fprintf (stderr, "master key file not given\n");
|
||||
return 1;
|
||||
}
|
||||
master_priv = GNUNET_CRYPTO_eddsa_key_create_from_file (masterkeyfile);
|
||||
if (NULL == master_priv)
|
||||
{
|
||||
fprintf (stderr, "master key invalid\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
master_pub = GNUNET_new (struct GNUNET_CRYPTO_EddsaPublicKey);
|
||||
GNUNET_CRYPTO_eddsa_key_get_public (master_priv, master_pub);
|
||||
|
||||
// check if key from file matches the one from the configuration
|
||||
{
|
||||
struct GNUNET_CRYPTO_EddsaPublicKey master_pub_from_cfg;
|
||||
if (GNUNET_OK != TALER_configuration_get_data (kcfg, "mint", "master_pub",
|
||||
&master_pub_from_cfg,
|
||||
sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
|
||||
{
|
||||
fprintf (stderr, "master key missing in configuration (mint.master_pub)\n");
|
||||
return 1;
|
||||
}
|
||||
if (0 != memcmp (master_pub, &master_pub_from_cfg, sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)))
|
||||
{
|
||||
fprintf (stderr, "Mismatch between key from mint configuration and master private key file from command line.\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (GNUNET_OK != mint_keys_update ())
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
215
src/mint/taler-mint-reservemod.c
Normal file
215
src/mint/taler-mint-reservemod.c
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file taler-mint-reservemod.c
|
||||
* @brief Modify reserves.
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <libpq-fe.h>
|
||||
#include "taler_util.h"
|
||||
#include "taler_signatures.h"
|
||||
#include "mint.h"
|
||||
|
||||
static char *mintdir;
|
||||
static struct GNUNET_CRYPTO_EddsaPublicKey *reserve_pub;
|
||||
static struct GNUNET_CONFIGURATION_Handle *kcfg;
|
||||
static PGconn *db_conn;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create a new or add to existing reserve.
|
||||
* Fails if currencies do not match.
|
||||
*
|
||||
* @param denom denomination to add
|
||||
*
|
||||
* @return ...
|
||||
*/
|
||||
int
|
||||
reservemod_add (struct TALER_Amount denom)
|
||||
{
|
||||
PGresult *result;
|
||||
{
|
||||
const void *param_values[] = { reserve_pub };
|
||||
int param_lengths[] = {sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)};
|
||||
int param_formats[] = {1};
|
||||
result = PQexecParams (db_conn,
|
||||
"select balance_value, balance_fraction, balance_currency from reserves where reserve_pub=$1 limit 1;",
|
||||
1, NULL, (const char * const *) param_values, param_lengths, param_formats, 1);
|
||||
}
|
||||
|
||||
if (PGRES_TUPLES_OK != PQresultStatus (result))
|
||||
{
|
||||
fprintf (stderr, "Select failed: %s\n", PQresultErrorMessage (result));
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (0 == PQntuples (result))
|
||||
{
|
||||
struct GNUNET_TIME_AbsoluteNBO exnbo;
|
||||
exnbo = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_add ( GNUNET_TIME_absolute_get (), GNUNET_TIME_UNIT_YEARS));
|
||||
|
||||
uint32_t value = htonl (denom.value);
|
||||
uint32_t fraction = htonl (denom.fraction);
|
||||
const void *param_values[] = {
|
||||
reserve_pub,
|
||||
&value,
|
||||
&fraction,
|
||||
denom.currency,
|
||||
&exnbo};
|
||||
int param_lengths[] = {32, 4, 4, strlen(denom.currency), 8};
|
||||
int param_formats[] = {1, 1, 1, 1, 1};
|
||||
result = PQexecParams (db_conn,
|
||||
"insert into reserves (reserve_pub, balance_value, balance_fraction, balance_currency, "
|
||||
" expiration_date )"
|
||||
"values ($1,$2,$3,$4,$5);",
|
||||
5, NULL, (const char **) param_values, param_lengths, param_formats, 1);
|
||||
|
||||
if (PGRES_COMMAND_OK != PQresultStatus (result))
|
||||
{
|
||||
fprintf (stderr, "Insert failed: %s\n", PQresultErrorMessage (result));
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
struct TALER_Amount old_denom;
|
||||
struct TALER_Amount new_denom;
|
||||
struct TALER_AmountNBO new_denom_nbo;
|
||||
int denom_indices[] = {0, 1, 2};
|
||||
int param_lengths[] = {4, 4, 32};
|
||||
int param_formats[] = {1, 1, 1};
|
||||
const void *param_values[] = {
|
||||
&new_denom_nbo.value,
|
||||
&new_denom_nbo.fraction,
|
||||
reserve_pub
|
||||
};
|
||||
|
||||
GNUNET_assert (GNUNET_OK == TALER_TALER_DB_extract_amount (result, 0, denom_indices, &old_denom));
|
||||
new_denom = TALER_amount_add (old_denom, denom);
|
||||
new_denom_nbo = TALER_amount_hton (new_denom);
|
||||
result = PQexecParams (db_conn,
|
||||
"UPDATE reserves "
|
||||
"SET balance_value = $1, balance_fraction = $2, "
|
||||
" status_sig = NULL, status_sign_pub = NULL "
|
||||
"WHERE reserve_pub = $3 ",
|
||||
3, NULL, (const char **) param_values, param_lengths, param_formats, 1);
|
||||
|
||||
if (PGRES_COMMAND_OK != PQresultStatus (result))
|
||||
{
|
||||
fprintf (stderr, "Update failed: %s\n", PQresultErrorMessage (result));
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
if (0 != strcmp ("1", PQcmdTuples (result)))
|
||||
{
|
||||
fprintf (stderr, "Update failed (updated '%s' tupes instead of '1')\n",
|
||||
PQcmdTuples (result));
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The main function of the reservemod tool
|
||||
*
|
||||
* @param argc number of arguments from the command line
|
||||
* @param argv command line arguments
|
||||
* @return 0 ok, 1 on error
|
||||
*/
|
||||
int
|
||||
main (int argc, char *const *argv)
|
||||
{
|
||||
static char *reserve_pub_str;
|
||||
static char *add_str;
|
||||
static const struct GNUNET_GETOPT_CommandLineOption options[] = {
|
||||
GNUNET_GETOPT_OPTION_HELP ("gnunet-mint-keyup OPTIONS"),
|
||||
{'d', "mint-dir", "DIR",
|
||||
"mint directory with keys to update", 1,
|
||||
&GNUNET_GETOPT_set_filename, &mintdir},
|
||||
{'R', "reserve", "KEY",
|
||||
"reserve (public key) to modify", 1,
|
||||
&GNUNET_GETOPT_set_string, &reserve_pub_str},
|
||||
{'a', "add", "DENOM",
|
||||
"value to add", 1,
|
||||
&GNUNET_GETOPT_set_string, &add_str},
|
||||
GNUNET_GETOPT_OPTION_END
|
||||
};
|
||||
char *TALER_MINT_db_connection_cfg_str;
|
||||
|
||||
GNUNET_assert (GNUNET_OK == GNUNET_log_setup ("taler-mint-keycheck", "WARNING", NULL));
|
||||
|
||||
if (GNUNET_GETOPT_run ("taler-mint-keyup", options, argc, argv) < 0)
|
||||
return 1;
|
||||
if (NULL == mintdir)
|
||||
{
|
||||
fprintf (stderr, "mint directory not given\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
reserve_pub = GNUNET_new (struct GNUNET_CRYPTO_EddsaPublicKey);
|
||||
if ((NULL == reserve_pub_str) ||
|
||||
(GNUNET_OK != GNUNET_STRINGS_string_to_data (reserve_pub_str,
|
||||
strlen (reserve_pub_str),
|
||||
reserve_pub,
|
||||
sizeof (struct GNUNET_CRYPTO_EddsaPublicKey))))
|
||||
{
|
||||
fprintf (stderr, "reserve key invalid\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
kcfg = TALER_MINT_config_load (mintdir);
|
||||
if (NULL == kcfg)
|
||||
{
|
||||
fprintf (stderr, "can't load mint configuration\n");
|
||||
return 1;
|
||||
}
|
||||
if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (kcfg, "mint", "db", &TALER_MINT_db_connection_cfg_str))
|
||||
{
|
||||
fprintf (stderr, "db configuration string not found\n");
|
||||
return 42;
|
||||
}
|
||||
db_conn = PQconnectdb (TALER_MINT_db_connection_cfg_str);
|
||||
if (CONNECTION_OK != PQstatus (db_conn))
|
||||
{
|
||||
fprintf (stderr, "db connection failed: %s\n", PQerrorMessage (db_conn));
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (NULL != add_str)
|
||||
{
|
||||
struct TALER_Amount add_value;
|
||||
if (GNUNET_OK != TALER_string_to_amount (add_str, &add_value))
|
||||
{
|
||||
fprintf (stderr, "could not read value\n");
|
||||
return 1;
|
||||
}
|
||||
if (GNUNET_OK != reservemod_add (add_value))
|
||||
{
|
||||
fprintf (stderr, "adding value failed\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
211
src/mint/test_mint_api.c
Normal file
211
src/mint/test_mint_api.c
Normal file
@ -0,0 +1,211 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file mint/test_mint_api.c
|
||||
* @brief testcase to test mint's HTTP API interface
|
||||
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#include "taler_util.h"
|
||||
#include "taler_mint_service.h"
|
||||
|
||||
struct TALER_MINT_Context *ctx;
|
||||
|
||||
struct TALER_MINT_Handle *mint;
|
||||
|
||||
struct TALER_MINT_KeysGetHandle *dkey_get;
|
||||
|
||||
struct TALER_MINT_DepositHandle *dh;
|
||||
|
||||
static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
|
||||
|
||||
static int result;
|
||||
|
||||
|
||||
static void
|
||||
do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
|
||||
{
|
||||
shutdown_task = GNUNET_SCHEDULER_NO_TASK;
|
||||
if (NULL != dkey_get)
|
||||
TALER_MINT_keys_get_cancel (dkey_get);
|
||||
dkey_get = NULL;
|
||||
if (NULL != dh)
|
||||
TALER_MINT_deposit_submit_cancel (dh);
|
||||
dh = NULL;
|
||||
TALER_MINT_disconnect (mint);
|
||||
mint = NULL;
|
||||
TALER_MINT_cleanup (ctx);
|
||||
ctx = NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callbacks of this type are used to serve the result of submitting a deposit
|
||||
* permission object to a mint
|
||||
*
|
||||
* @param cls closure
|
||||
* @param status 1 for successful deposit, 2 for retry, 0 for failure
|
||||
* @param obj the received JSON object; can be NULL if it cannot be constructed
|
||||
* from the reply
|
||||
* @param emsg in case of unsuccessful deposit, this contains a human readable
|
||||
* explanation.
|
||||
*/
|
||||
static void
|
||||
deposit_status (void *cls,
|
||||
int status,
|
||||
json_t *obj,
|
||||
char *emsg)
|
||||
{
|
||||
char *json_enc;
|
||||
|
||||
dh = NULL;
|
||||
json_enc = NULL;
|
||||
if (NULL != obj)
|
||||
{
|
||||
json_enc = json_dumps (obj, JSON_INDENT(2));
|
||||
fprintf (stderr, "%s", json_enc);
|
||||
}
|
||||
if (1 == status)
|
||||
result = GNUNET_OK;
|
||||
else
|
||||
GNUNET_break (0);
|
||||
if (NULL != emsg)
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Deposit failed: %s\n", emsg);
|
||||
GNUNET_SCHEDULER_shutdown ();
|
||||
}
|
||||
/**
|
||||
* Functions of this type are called to signal completion of an asynchronous call.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param emsg if the asynchronous call could not be completed due to an error,
|
||||
* this parameter contains a human readable error message
|
||||
*/
|
||||
static void
|
||||
cont (void *cls, const char *emsg)
|
||||
{
|
||||
json_t *dp;
|
||||
char rnd_32[32];
|
||||
char rnd_64[64];
|
||||
char *enc_32;
|
||||
char *enc_64;
|
||||
|
||||
GNUNET_assert (NULL == cls);
|
||||
dkey_get = NULL;
|
||||
if (NULL != emsg)
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s\n", emsg);
|
||||
|
||||
enc_32 = TALER_data_to_string_alloc (rnd_32, sizeof (rnd_32));
|
||||
enc_64 = TALER_data_to_string_alloc (rnd_64, sizeof (rnd_64));
|
||||
dp = json_pack ("{s:s s:o s:s s:s s:s s:s s:s s:s s:s s:s}",
|
||||
"type", "DIRECT_DEPOSIT",
|
||||
"wire", json_pack ("{s:s}", "type", "SEPA"),
|
||||
"C", enc_32,
|
||||
"K", enc_32,
|
||||
"ubsig", enc_64,
|
||||
"M", enc_32,
|
||||
"H_a", enc_64,
|
||||
"H_wire", enc_64,
|
||||
"csig", enc_64,
|
||||
"m", "B1C5GP2RB1C5G");
|
||||
GNUNET_free (enc_32);
|
||||
GNUNET_free (enc_64);
|
||||
dh = TALER_MINT_deposit_submit_json (mint,
|
||||
deposit_status,
|
||||
NULL,
|
||||
dp);
|
||||
json_decref (dp);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Functions of this type are called to provide the retrieved signing and
|
||||
* denomination keys of the mint. No TALER_MINT_*() functions should be called
|
||||
* in this callback.
|
||||
*
|
||||
* @param cls closure passed to TALER_MINT_keys_get()
|
||||
* @param sign_keys NULL-terminated array of pointers to the mint's signing
|
||||
* keys. NULL if no signing keys are retrieved.
|
||||
* @param denom_keys NULL-terminated array of pointers to the mint's
|
||||
* denomination keys; will be NULL if no signing keys are retrieved.
|
||||
*/
|
||||
static void
|
||||
read_denom_key (void *cls,
|
||||
struct TALER_MINT_SigningPublicKey **sign_keys,
|
||||
struct TALER_MINT_DenomPublicKey **denom_keys)
|
||||
{
|
||||
unsigned int cnt;
|
||||
GNUNET_assert (NULL == cls);
|
||||
#define ERR(cond) do { if(!(cond)) break; GNUNET_break (0); return; } while (0)
|
||||
ERR (NULL == sign_keys);
|
||||
ERR (NULL == denom_keys);
|
||||
for (cnt = 0; NULL != sign_keys[cnt]; cnt++)
|
||||
GNUNET_free (sign_keys[cnt]);
|
||||
ERR (0 == cnt);
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read %u signing keys\n", cnt);
|
||||
GNUNET_free (sign_keys);
|
||||
for (cnt = 0; NULL != denom_keys[cnt]; cnt++)
|
||||
GNUNET_free (denom_keys[cnt]);
|
||||
ERR (0 == cnt);
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read %u denomination keys\n", cnt);
|
||||
GNUNET_free (denom_keys);
|
||||
#undef ERR
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Main function that will be run by the scheduler.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param args remaining command-line arguments
|
||||
* @param cfgfile name of the configuration file used (for saving, can be NULL!)
|
||||
* @param config configuration
|
||||
*/
|
||||
static void
|
||||
run (void *cls, char *const *args, const char *cfgfile,
|
||||
const struct GNUNET_CONFIGURATION_Handle *config)
|
||||
{
|
||||
ctx = TALER_MINT_init ();
|
||||
mint = TALER_MINT_connect (ctx, "localhost", 4241, NULL);
|
||||
GNUNET_assert (NULL != mint);
|
||||
dkey_get = TALER_MINT_keys_get (mint,
|
||||
&read_denom_key, NULL,
|
||||
&cont, NULL);
|
||||
GNUNET_assert (NULL != dkey_get);
|
||||
shutdown_task =
|
||||
GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply
|
||||
(GNUNET_TIME_UNIT_SECONDS, 5),
|
||||
&do_shutdown, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char * const *argv)
|
||||
{
|
||||
static struct GNUNET_GETOPT_CommandLineOption options[] = {
|
||||
GNUNET_GETOPT_OPTION_END
|
||||
};
|
||||
|
||||
result = GNUNET_SYSERR;
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PROGRAM_run (argc, argv, "test-mint-api",
|
||||
gettext_noop
|
||||
("Testcase to test mint's HTTP API interface"),
|
||||
options, &run, NULL))
|
||||
return 3;
|
||||
return (GNUNET_OK == result) ? 0 : 1;
|
||||
}
|
83
src/mint/test_mint_common.c
Normal file
83
src/mint/test_mint_common.c
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 GNUnet e. V. (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file mint/test_mint_common.c
|
||||
* @brief test cases for some functions in mint/mint_common.c
|
||||
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#include "gnunet/gnunet_util_lib.h"
|
||||
#include "taler_rsa.h"
|
||||
#include "mint.h"
|
||||
|
||||
#define EXITIF(cond) \
|
||||
do { \
|
||||
if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
|
||||
} while (0)
|
||||
|
||||
int
|
||||
main (int argc, const char *const argv[])
|
||||
{
|
||||
struct TALER_MINT_DenomKeyIssue dki;
|
||||
struct TALER_RSA_PrivateKeyBinaryEncoded *enc;
|
||||
struct TALER_MINT_DenomKeyIssue dki_read;
|
||||
struct TALER_RSA_PrivateKeyBinaryEncoded *enc_read;
|
||||
char *tmpfile;
|
||||
|
||||
int ret;
|
||||
|
||||
ret = 1;
|
||||
enc = NULL;
|
||||
enc_read = NULL;
|
||||
tmpfile = NULL;
|
||||
dki.denom_priv = NULL;
|
||||
dki_read.denom_priv = NULL;
|
||||
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
|
||||
&dki.signature,
|
||||
sizeof (dki) - offsetof (struct TALER_MINT_DenomKeyIssue,
|
||||
signature));
|
||||
dki.denom_priv = TALER_RSA_key_create ();
|
||||
EXITIF (NULL == (enc = TALER_RSA_encode_key (dki.denom_priv)));
|
||||
EXITIF (NULL == (tmpfile = GNUNET_DISK_mktemp ("test_mint_common")));
|
||||
EXITIF (GNUNET_OK != TALER_MINT_write_denom_key (tmpfile, &dki));
|
||||
EXITIF (GNUNET_OK != TALER_MINT_read_denom_key (tmpfile, &dki_read));
|
||||
EXITIF (NULL == (enc_read = TALER_RSA_encode_key (dki_read.denom_priv)));
|
||||
EXITIF (enc->len != enc_read->len);
|
||||
EXITIF (0 != memcmp (enc,
|
||||
enc_read,
|
||||
ntohs(enc->len)));
|
||||
EXITIF (0 != memcmp (&dki.signature,
|
||||
&dki_read.signature,
|
||||
sizeof (dki) - offsetof (struct TALER_MINT_DenomKeyIssue,
|
||||
signature)));
|
||||
ret = 0;
|
||||
|
||||
EXITIF_exit:
|
||||
GNUNET_free_non_null (enc);
|
||||
if (NULL != tmpfile)
|
||||
{
|
||||
(void) unlink (tmpfile);
|
||||
GNUNET_free (tmpfile);
|
||||
}
|
||||
GNUNET_free_non_null (enc_read);
|
||||
if (NULL != dki.denom_priv)
|
||||
TALER_RSA_key_free (dki.denom_priv);
|
||||
if (NULL != dki_read.denom_priv)
|
||||
TALER_RSA_key_free (dki_read.denom_priv);
|
||||
return ret;
|
||||
}
|
149
src/mint/test_mint_deposits.c
Normal file
149
src/mint/test_mint_deposits.c
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file mint/test_mint_deposits.c
|
||||
* @brief testcase for mint deposits
|
||||
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#include <libpq-fe.h>
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include "mint_db.h"
|
||||
|
||||
#define DB_URI "postgres:///taler"
|
||||
|
||||
/**
|
||||
* Shorthand for exit jumps.
|
||||
*/
|
||||
#define EXITIF(cond) \
|
||||
do { \
|
||||
if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
|
||||
} while (0)
|
||||
|
||||
|
||||
/**
|
||||
* DB connection handle
|
||||
*/
|
||||
static PGconn *conn;
|
||||
|
||||
/**
|
||||
* Should we not interact with a temporary table?
|
||||
*/
|
||||
static int persistent;
|
||||
|
||||
/**
|
||||
* Testcase result
|
||||
*/
|
||||
static int result;
|
||||
|
||||
|
||||
static void
|
||||
do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
|
||||
{
|
||||
if (NULL != conn)
|
||||
PQfinish (conn);
|
||||
conn = NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Main function that will be run by the scheduler.
|
||||
*
|
||||
* @param cls closure
|
||||
* @param args remaining command-line arguments
|
||||
* @param cfgfile name of the configuration file used (for saving, can be NULL!)
|
||||
* @param config configuration
|
||||
*/
|
||||
static void
|
||||
run (void *cls, char *const *args, const char *cfgfile,
|
||||
const struct GNUNET_CONFIGURATION_Handle *config)
|
||||
{
|
||||
static const char wire[] = "{"
|
||||
"\"type\":\"SEPA\","
|
||||
"\"IBAN\":\"DE67830654080004822650\","
|
||||
"\"NAME\":\"GNUNET E.V\","
|
||||
"\"BIC\":\"GENODEF1SRL\""
|
||||
"}";
|
||||
struct Deposit *deposit;
|
||||
struct Deposit *q_deposit;
|
||||
uint64_t transaction_id;
|
||||
|
||||
deposit = NULL;
|
||||
q_deposit = NULL;
|
||||
GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
|
||||
&do_shutdown, NULL);
|
||||
EXITIF (NULL == (conn = PQconnectdb(DB_URI)));
|
||||
EXITIF (GNUNET_OK != TALER_MINT_DB_init_deposits (conn, !persistent));
|
||||
EXITIF (GNUNET_OK != TALER_MINT_DB_prepare_deposits (conn));
|
||||
deposit = GNUNET_malloc (sizeof (struct Deposit) + sizeof (wire));
|
||||
/* Makeup a random coin public key */
|
||||
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK,
|
||||
deposit,
|
||||
sizeof (struct Deposit));
|
||||
/* Makeup a random 64bit transaction ID */
|
||||
transaction_id = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
|
||||
UINT64_MAX);
|
||||
deposit->transaction_id = GNUNET_htonll (transaction_id);
|
||||
/* Random amount */
|
||||
deposit->amount.value =
|
||||
htonl (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX));
|
||||
deposit->amount.fraction =
|
||||
htonl (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX));
|
||||
strcpy (deposit->amount.currency, "EUR");
|
||||
/* Copy wireformat */
|
||||
(void) memcpy (deposit->wire, wire, sizeof (wire));
|
||||
EXITIF (GNUNET_OK != TALER_MINT_DB_insert_deposit (conn,
|
||||
deposit));
|
||||
EXITIF (GNUNET_OK != TALER_MINT_DB_get_deposit (conn,
|
||||
&deposit->coin_pub,
|
||||
&q_deposit));
|
||||
EXITIF (0 != memcmp (deposit,
|
||||
q_deposit,
|
||||
sizeof (struct Deposit) - offsetof(struct Deposit,
|
||||
wire)));
|
||||
EXITIF (transaction_id != GNUNET_ntohll (q_deposit->transaction_id));
|
||||
result = GNUNET_OK;
|
||||
|
||||
EXITIF_exit:
|
||||
GNUNET_free_non_null (deposit);
|
||||
GNUNET_free_non_null (q_deposit);
|
||||
GNUNET_SCHEDULER_shutdown ();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *const argv[])
|
||||
{
|
||||
static const struct GNUNET_GETOPT_CommandLineOption options[] = {
|
||||
{'T', "persist", NULL,
|
||||
gettext_noop ("Use a persistent database table instead of a temporary one"),
|
||||
GNUNET_NO, &GNUNET_GETOPT_set_one, &persistent},
|
||||
GNUNET_GETOPT_OPTION_END
|
||||
};
|
||||
|
||||
|
||||
persistent = GNUNET_NO;
|
||||
result = GNUNET_SYSERR;
|
||||
if (GNUNET_OK !=
|
||||
GNUNET_PROGRAM_run (argc, argv,
|
||||
"test-mint-deposits",
|
||||
"testcase for mint deposits",
|
||||
options, &run, NULL))
|
||||
return 3;
|
||||
return (GNUNET_OK == result) ? 0 : 1;
|
||||
}
|
BIN
src/mint/test_mint_nayapaisa.ecc
Normal file
BIN
src/mint/test_mint_nayapaisa.ecc
Normal file
Binary file not shown.
1
src/mint/test_mint_nayapaisa/README
Normal file
1
src/mint/test_mint_nayapaisa/README
Normal file
@ -0,0 +1 @@
|
||||
This directory is a template for the mint directory.
|
6
src/mint/test_mint_nayapaisa/config/mint-common.conf
Normal file
6
src/mint/test_mint_nayapaisa/config/mint-common.conf
Normal file
@ -0,0 +1,6 @@
|
||||
[mint]
|
||||
db = postgres:///taler
|
||||
port = 4241
|
||||
master_pub = 6ZE0HEY2M0FWP61M0470HYBF4K6RRD5DP54372PD2TN9N9VX2VJG
|
||||
refresh_security_parameter = 3
|
||||
|
79
src/mint/test_mint_nayapaisa/config/mint-keyup.conf
Normal file
79
src/mint/test_mint_nayapaisa/config/mint-keyup.conf
Normal file
@ -0,0 +1,79 @@
|
||||
[mint_keys]
|
||||
|
||||
# how long is one signkey valid?
|
||||
signkey_duration = 4 weeks
|
||||
|
||||
# how long do we generate denomination and signing keys
|
||||
# ahead of time?
|
||||
lookahead_sign = 32 weeks 1 day
|
||||
|
||||
# how long do we provide to clients denomination and signing keys
|
||||
# ahead of time?
|
||||
lookahead_provide = 4 weeks 1 day
|
||||
|
||||
# what coin types do we have available?
|
||||
coin_types = default_eur_ct_10 default_eur_5 default_eur_10 default_eur_1000
|
||||
|
||||
|
||||
|
||||
[mint_denom_duration_overlap]
|
||||
default_eur_ct_10 = 5 minutes
|
||||
default_eur_5 = 5 minutes
|
||||
default_eur_10 = 5 minutes
|
||||
default_eur_1000 = 5 minutes
|
||||
|
||||
|
||||
|
||||
[mint_denom_value]
|
||||
default_eur_ct_10 = EUR:0.10
|
||||
default_eur_5 = EUR:5
|
||||
default_eur_10 = EUR:10
|
||||
default_eur_1000 = EUR:1000
|
||||
|
||||
|
||||
|
||||
[mint_denom_duration_withdraw]
|
||||
default_eur_ct_10 = 7 days
|
||||
default_eur_5 = 7 days
|
||||
default_eur_10 = 7 days
|
||||
default_eur_1000 = 1 day
|
||||
|
||||
|
||||
|
||||
[mint_denom_duration_spend]
|
||||
default_eur_ct_10 = 30 days
|
||||
default_eur_5 = 30 days
|
||||
default_eur_10 = 30 days
|
||||
default_eur_1000 = 30 day
|
||||
|
||||
|
||||
|
||||
[mint_denom_fee_withdraw]
|
||||
default_eur_ct_10 = EUR:0.01
|
||||
default_eur_5 = EUR:0.01
|
||||
default_eur_10 = EUR:0.01
|
||||
default_eur_1000 = EUR:0.01
|
||||
|
||||
|
||||
[mint_denom_fee_deposit]
|
||||
default_eur_ct_10 = EUR:0.01
|
||||
default_eur_5 = EUR:0.01
|
||||
default_eur_10 = EUR:0.01
|
||||
default_eur_1000 = EUR:0.01
|
||||
|
||||
|
||||
|
||||
[mint_denom_fee_refresh]
|
||||
default_eur_ct_10 = EUR:0.01
|
||||
default_eur_5 = EUR:0.01
|
||||
default_eur_10 = EUR:0.01
|
||||
default_eur_1000 = EUR:0.01
|
||||
|
||||
|
||||
|
||||
[mint_denom_kappa]
|
||||
default_eur_ct_10 = 3
|
||||
default_eur_5 = 3
|
||||
default_eur_10 = 3
|
||||
default_eur_1000 = 5
|
||||
|
1
src/mint/test_mint_nyadirahim.ecc
Normal file
1
src/mint/test_mint_nyadirahim.ecc
Normal file
@ -0,0 +1 @@
|
||||
<EFBFBD>W<EFBFBD>B<EFBFBD><EFBFBD>f<EFBFBD> <20><>r<EFBFBD><EFBFBD>Ќ<1E><>:<3A><1E>V<07>j
|
1
src/mint/test_mint_nyadirahim/README
Normal file
1
src/mint/test_mint_nyadirahim/README
Normal file
@ -0,0 +1 @@
|
||||
This directory is a template for the mint directory.
|
6
src/mint/test_mint_nyadirahim/config/mint-common.conf
Normal file
6
src/mint/test_mint_nyadirahim/config/mint-common.conf
Normal file
@ -0,0 +1,6 @@
|
||||
[mint]
|
||||
db = postgres:///taler
|
||||
port = 4241
|
||||
master_pub = 7995WKK71KPKTBBMA5BHNBSZFGNRZPYNXDJMQ8EK86V9598H03TG
|
||||
refresh_security_parameter = 3
|
||||
|
79
src/mint/test_mint_nyadirahim/config/mint-keyup.conf
Normal file
79
src/mint/test_mint_nyadirahim/config/mint-keyup.conf
Normal file
@ -0,0 +1,79 @@
|
||||
[mint_keys]
|
||||
|
||||
# how long is one signkey valid?
|
||||
signkey_duration = 4 weeks
|
||||
|
||||
# how long do we generate denomination and signing keys
|
||||
# ahead of time?
|
||||
lookahead_sign = 32 weeks 1 day
|
||||
|
||||
# how long do we provide to clients denomination and signing keys
|
||||
# ahead of time?
|
||||
lookahead_provide = 4 weeks 1 day
|
||||
|
||||
# what coin types do we have available?
|
||||
coin_types = default_eur_ct_10 default_eur_5 default_eur_10 default_eur_1000
|
||||
|
||||
|
||||
|
||||
[mint_denom_duration_overlap]
|
||||
default_eur_ct_10 = 5 minutes
|
||||
default_eur_5 = 5 minutes
|
||||
default_eur_10 = 5 minutes
|
||||
default_eur_1000 = 5 minutes
|
||||
|
||||
|
||||
|
||||
[mint_denom_value]
|
||||
default_eur_ct_10 = EUR:0.10
|
||||
default_eur_5 = EUR:5
|
||||
default_eur_10 = EUR:10
|
||||
default_eur_1000 = EUR:1000
|
||||
|
||||
|
||||
|
||||
[mint_denom_duration_withdraw]
|
||||
default_eur_ct_10 = 7 days
|
||||
default_eur_5 = 7 days
|
||||
default_eur_10 = 7 days
|
||||
default_eur_1000 = 1 day
|
||||
|
||||
|
||||
|
||||
[mint_denom_duration_spend]
|
||||
default_eur_ct_10 = 30 days
|
||||
default_eur_5 = 30 days
|
||||
default_eur_10 = 30 days
|
||||
default_eur_1000 = 30 day
|
||||
|
||||
|
||||
|
||||
[mint_denom_fee_withdraw]
|
||||
default_eur_ct_10 = EUR:0.01
|
||||
default_eur_5 = EUR:0.01
|
||||
default_eur_10 = EUR:0.01
|
||||
default_eur_1000 = EUR:0.01
|
||||
|
||||
|
||||
[mint_denom_fee_deposit]
|
||||
default_eur_ct_10 = EUR:0.01
|
||||
default_eur_5 = EUR:0.01
|
||||
default_eur_10 = EUR:0.01
|
||||
default_eur_1000 = EUR:0.01
|
||||
|
||||
|
||||
|
||||
[mint_denom_fee_refresh]
|
||||
default_eur_ct_10 = EUR:0.01
|
||||
default_eur_5 = EUR:0.01
|
||||
default_eur_10 = EUR:0.01
|
||||
default_eur_1000 = EUR:0.01
|
||||
|
||||
|
||||
|
||||
[mint_denom_kappa]
|
||||
default_eur_ct_10 = 3
|
||||
default_eur_5 = 3
|
||||
default_eur_10 = 3
|
||||
default_eur_1000 = 5
|
||||
|
39
src/util/Makefile.am
Normal file
39
src/util/Makefile.am
Normal file
@ -0,0 +1,39 @@
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/src/include $(LIBGCRYPT_CFLAGS) $(POSTGRESQL_CPPFLAGS)
|
||||
|
||||
lib_LTLIBRARIES = \
|
||||
libtalerutil.la
|
||||
|
||||
libtalerutil_la_SOURCES = \
|
||||
util.c \
|
||||
json.c \
|
||||
db.c \
|
||||
microhttpd.c \
|
||||
rsa.c
|
||||
|
||||
libtalerutil_la_LIBADD = \
|
||||
-lgnunetutil \
|
||||
$(LIBGCRYPT_LIBS) \
|
||||
-ljansson \
|
||||
-lmicrohttpd \
|
||||
-lpq
|
||||
|
||||
libtalerutil_la_LDFLAGS = \
|
||||
$(POSTGRESQL_LDFLAGS) \
|
||||
-version-info 0:0:0 \
|
||||
-export-dynamic -no-undefined
|
||||
|
||||
check_PROGRAMS = \
|
||||
test-hash-context \
|
||||
test-rsa
|
||||
|
||||
TESTS = \
|
||||
$(check_PROGRAMS)
|
||||
|
||||
test_hash_context_SOURCES = test_hash_context.c
|
||||
test_hash_context_CPPFLAGS = $(AM_CPPFLAGS) $(LIBGCRYPT_CFLAGS)
|
||||
test_hash_context_LDADD = libtalerutil.la \
|
||||
-lgnunetutil $(LIBGCRYPT_LIBS)
|
||||
|
||||
test_rsa_SOURCES = test_rsa.c
|
||||
test_rsa_LDADD = libtalerutil.la \
|
||||
-lgnunetutil $(LIBGCRYPT_LIBS)
|
196
src/util/db.c
Normal file
196
src/util/db.c
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @file util/db.c
|
||||
* @brief helper functions for DB interactions
|
||||
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||
* @author Florian Dold
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include "taler_db_lib.h"
|
||||
|
||||
|
||||
/**
|
||||
* Execute a prepared statement.
|
||||
*/
|
||||
PGresult *
|
||||
TALER_DB_exec_prepared (PGconn *db_conn,
|
||||
const char *name,
|
||||
const struct TALER_DB_QueryParam *params)
|
||||
{
|
||||
unsigned len;
|
||||
unsigned i;
|
||||
|
||||
/* count the number of parameters */
|
||||
|
||||
{
|
||||
const struct TALER_DB_QueryParam *x;
|
||||
for (len = 0, x = params;
|
||||
x->more;
|
||||
len +=1, x += 1);
|
||||
}
|
||||
|
||||
/* new scope to allow stack allocation without alloca */
|
||||
|
||||
{
|
||||
void *param_values[len];
|
||||
int param_lengths[len];
|
||||
int param_formats[len];
|
||||
|
||||
for (i = 0; i < len; i += 1)
|
||||
{
|
||||
param_values[i] = (void *) params[i].data;
|
||||
param_lengths[i] = params[i].size;
|
||||
param_formats[i] = 1;
|
||||
}
|
||||
return PQexecPrepared (db_conn, name, len,
|
||||
(const char **) param_values, param_lengths, param_formats, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract results from a query result according to the given specification.
|
||||
* If colums are NULL, the destination is not modified, and GNUNET_NO
|
||||
* is returned.
|
||||
*
|
||||
* @return
|
||||
* GNUNET_YES if all results could be extracted
|
||||
* GNUNET_NO if at least one result was NULL
|
||||
* GNUNET_SYSERR if a result was invalid (non-existing field)
|
||||
*/
|
||||
int
|
||||
TALER_DB_extract_result (PGresult *result,
|
||||
struct TALER_DB_ResultSpec *rs,
|
||||
int row)
|
||||
{
|
||||
int had_null = GNUNET_NO;
|
||||
|
||||
for (; NULL != rs->fname; rs += 1)
|
||||
{
|
||||
int fnum;
|
||||
fnum = PQfnumber (result, rs->fname);
|
||||
if (fnum < 0)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "field '%s' does not exist in result\n", rs->fname);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
/* if a field is null, continue but
|
||||
* remember that we now return a different result */
|
||||
|
||||
if (PQgetisnull (result, row, fnum))
|
||||
{
|
||||
had_null = GNUNET_YES;
|
||||
continue;
|
||||
}
|
||||
const char *res;
|
||||
if (rs->dst_size != PQgetlength (result, row, fnum))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "field '%s' has wrong size (got %u, expected %u)\n",
|
||||
rs->fname, (int) PQgetlength (result, row, fnum), (int) rs->dst_size);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
res = PQgetvalue (result, row, fnum);
|
||||
GNUNET_assert (NULL != res);
|
||||
memcpy (rs->dst, res, rs->dst_size);
|
||||
}
|
||||
if (GNUNET_YES == had_null)
|
||||
return GNUNET_NO;
|
||||
return GNUNET_YES;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
TALER_DB_field_isnull (PGresult *result,
|
||||
int row,
|
||||
const char *fname)
|
||||
{
|
||||
int fnum;
|
||||
fnum = PQfnumber (result, fname);
|
||||
GNUNET_assert (fnum >= 0);
|
||||
if (PQgetisnull (result, row, fnum))
|
||||
return GNUNET_YES;
|
||||
return GNUNET_NO;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
TALER_DB_extract_amount_nbo (PGresult *result,
|
||||
int row,
|
||||
const char *val_name,
|
||||
const char *frac_name,
|
||||
const char *curr_name,
|
||||
struct TALER_AmountNBO *r_amount_nbo)
|
||||
{
|
||||
int val_num;
|
||||
int frac_num;
|
||||
int curr_num;
|
||||
int len;
|
||||
|
||||
GNUNET_assert (NULL != strstr (val_name, "_val"));
|
||||
GNUNET_assert (NULL != strstr (frac_name, "_frac"));
|
||||
GNUNET_assert (NULL != strstr (curr_name, "_curr"));
|
||||
|
||||
val_num = PQfnumber (result, val_name);
|
||||
GNUNET_assert (val_num >= 0);
|
||||
frac_num = PQfnumber (result, frac_name);
|
||||
GNUNET_assert (frac_num >= 0);
|
||||
curr_num = PQfnumber (result, curr_name);
|
||||
GNUNET_assert (curr_num >= 0);
|
||||
|
||||
r_amount_nbo->value = *(uint32_t *) PQgetvalue (result, row, val_num);
|
||||
r_amount_nbo->fraction = *(uint32_t *) PQgetvalue (result, row, frac_num);
|
||||
memset (r_amount_nbo->currency, 0, TALER_CURRENCY_LEN);
|
||||
// FIXME: overflow?
|
||||
len = PQgetlength (result, row, curr_num);
|
||||
len = GNUNET_MIN (TALER_CURRENCY_LEN, len);
|
||||
memcpy (r_amount_nbo->currency, PQgetvalue (result, row, curr_num), len);
|
||||
r_amount_nbo->currency[TALER_CURRENCY_LEN - 1] = '\0';
|
||||
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
TALER_DB_extract_amount (PGresult *result,
|
||||
int row,
|
||||
const char *val_name,
|
||||
const char *frac_name,
|
||||
const char *curr_name,
|
||||
struct TALER_Amount *r_amount)
|
||||
{
|
||||
struct TALER_AmountNBO amount_nbo;
|
||||
|
||||
(void)
|
||||
TALER_DB_extract_amount_nbo (result,
|
||||
row,
|
||||
val_name,
|
||||
frac_name,
|
||||
curr_name,
|
||||
&amount_nbo);
|
||||
r_amount->value = ntohl (amount_nbo.value);
|
||||
r_amount->fraction = ntohl (amount_nbo.fraction);
|
||||
(void) strncpy (r_amount->currency, amount_nbo.currency, TALER_CURRENCY_LEN);
|
||||
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
/* end of util/db.c */
|
194
src/util/json.c
Normal file
194
src/util/json.c
Normal file
@ -0,0 +1,194 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file util/json.c
|
||||
* @brief helper functions for JSON processing using libjansson
|
||||
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include "taler_util.h"
|
||||
#include "taler_json_lib.h"
|
||||
|
||||
/**
|
||||
* Shorthand for exit jumps.
|
||||
*/
|
||||
#define EXITIF(cond) \
|
||||
do { \
|
||||
if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Print JSON parsing related error information
|
||||
*/
|
||||
#define WARN_JSON(error) \
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, \
|
||||
"JSON parsing failed at %s:%u: %s (%s)", \
|
||||
__FILE__, __LINE__, error.text, error.source)
|
||||
|
||||
/**
|
||||
* Shorthand for JSON parsing related exit jumps.
|
||||
*/
|
||||
#define UNPACK_EXITIF(cond) \
|
||||
do { \
|
||||
if (cond) { WARN_JSON(error); goto EXITIF_exit; } \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Convert a TALER amount to a JSON
|
||||
* object.
|
||||
*
|
||||
* @param amount the amount
|
||||
* @return a json object describing the amount
|
||||
*/
|
||||
json_t *
|
||||
TALER_JSON_from_amount (struct TALER_Amount amount)
|
||||
{
|
||||
json_t *j;
|
||||
j = json_pack ("{s: s, s:I, s:I}",
|
||||
"currency", amount.currency,
|
||||
"value", (json_int_t) amount.value,
|
||||
"fraction", (json_int_t) amount.fraction);
|
||||
GNUNET_assert (NULL != j);
|
||||
return j;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert absolute timestamp to a json string.
|
||||
*
|
||||
* @param the time stamp
|
||||
* @return a json string with the timestamp in @a stamp
|
||||
*/
|
||||
json_t *
|
||||
TALER_JSON_from_abs (struct GNUNET_TIME_Absolute stamp)
|
||||
{
|
||||
json_t *j;
|
||||
char *mystr;
|
||||
int ret;
|
||||
ret = GNUNET_asprintf (&mystr, "%llu",
|
||||
(long long) (stamp.abs_value_us / (1000 * 1000)));
|
||||
GNUNET_assert (ret > 0);
|
||||
j = json_string (mystr);
|
||||
GNUNET_free (mystr);
|
||||
return j;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Convert binary data to a JSON string
|
||||
* with the base32crockford encoding.
|
||||
*
|
||||
* @param data binary data
|
||||
* @param size size of @a data in bytes
|
||||
* @return json string that encodes @a data
|
||||
*/
|
||||
json_t *
|
||||
TALER_JSON_from_data (const void *data, size_t size)
|
||||
{
|
||||
char *buf;
|
||||
json_t *json;
|
||||
buf = TALER_data_to_string_alloc (data, size);
|
||||
json = json_string (buf);
|
||||
GNUNET_free (buf);
|
||||
return json;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse given JSON object to Amount
|
||||
*
|
||||
* @param json the json object representing Amount
|
||||
* @param r_amount where the amount has to be written
|
||||
* @return GNUNET_OK upon successful parsing; GNUNET_SYSERR upon error
|
||||
*/
|
||||
int
|
||||
TALER_JSON_to_amount (json_t *json,
|
||||
struct TALER_Amount *r_amount)
|
||||
{
|
||||
char *currency;
|
||||
json_int_t value;
|
||||
json_int_t fraction;
|
||||
json_error_t error;
|
||||
|
||||
UNPACK_EXITIF (0 != json_unpack_ex (json, &error, JSON_STRICT,
|
||||
"{s:s, s:I, s:I}",
|
||||
"curreny", ¤cy,
|
||||
"value", &value,
|
||||
"fraction", &fraction));
|
||||
EXITIF (3 < strlen (currency));
|
||||
r_amount->value = (uint32_t) value;
|
||||
r_amount->fraction = (uint32_t) fraction;
|
||||
return GNUNET_OK;
|
||||
|
||||
EXITIF_exit:
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse given JSON object to Amount
|
||||
*
|
||||
* @param json the json object representing Amount
|
||||
* @param r_amount where the amount has to be written
|
||||
* @return GNUNET_OK upon successful parsing; GNUNET_SYSERR upon error
|
||||
*/
|
||||
int
|
||||
TALER_JSON_to_abs (json_t *json,
|
||||
struct GNUNET_TIME_Absolute *abs)
|
||||
{
|
||||
const char *str;
|
||||
unsigned long long abs_value_s;
|
||||
|
||||
GNUNET_assert (NULL != abs);
|
||||
EXITIF (NULL == (str = json_string_value (json)));
|
||||
EXITIF (1 > sscanf (str, "%llu", &abs_value_s));
|
||||
abs->abs_value_us = abs_value_s * 1000 * 1000;
|
||||
return GNUNET_OK;
|
||||
|
||||
EXITIF_exit:
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse given JSON object to data
|
||||
*
|
||||
* @param json the json object representing data
|
||||
* @param out the pointer to hold the parsed data.
|
||||
* @param out_size the size of r_data.
|
||||
* @return GNUNET_OK upon successful parsing; GNUNET_SYSERR upon error
|
||||
*/
|
||||
int
|
||||
TALER_JSON_to_data (json_t *json,
|
||||
void *out,
|
||||
size_t out_size)
|
||||
{
|
||||
const char *enc;
|
||||
unsigned int len;
|
||||
|
||||
EXITIF (NULL == (enc = json_string_value (json)));
|
||||
len = strlen (enc);
|
||||
EXITIF ((((len * 5) / 8) + ((((len * 5) % 8) == 0) ? 0 : 1)) == out_size);
|
||||
EXITIF (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, len, out, out_size));
|
||||
return GNUNET_OK;
|
||||
EXITIF_exit:
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
/* End of util/json.c */
|
417
src/util/microhttpd.c
Normal file
417
src/util/microhttpd.c
Normal file
@ -0,0 +1,417 @@
|
||||
#include "platform.h"
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include "taler_microhttpd_lib.h"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Initial size for POST
|
||||
* request buffer.
|
||||
*/
|
||||
#define REQUEST_BUFFER_INITIAL 1024
|
||||
|
||||
/**
|
||||
* Maximum POST request size
|
||||
*/
|
||||
#define REQUEST_BUFFER_MAX (1024*1024)
|
||||
|
||||
|
||||
/**
|
||||
* Buffer for POST requests.
|
||||
*/
|
||||
struct Buffer
|
||||
{
|
||||
/**
|
||||
* Allocated memory
|
||||
*/
|
||||
char *data;
|
||||
|
||||
/**
|
||||
* Number of valid bytes in buffer.
|
||||
*/
|
||||
size_t fill;
|
||||
|
||||
/**
|
||||
* Number of allocated bytes in buffer.
|
||||
*/
|
||||
size_t alloc;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a buffer.
|
||||
*
|
||||
* @param buf the buffer to initialize
|
||||
* @param data the initial data
|
||||
* @param data_size size of the initial data
|
||||
* @param alloc_size size of the buffer
|
||||
* @param max_size maximum size that the buffer can grow to
|
||||
* @return a GNUnet result code
|
||||
*/
|
||||
static int
|
||||
buffer_init (struct Buffer *buf, const void *data, size_t data_size, size_t alloc_size, size_t max_size)
|
||||
{
|
||||
if (data_size > max_size || alloc_size > max_size)
|
||||
return GNUNET_SYSERR;
|
||||
if (data_size > alloc_size)
|
||||
alloc_size = data_size;
|
||||
buf->data = GNUNET_malloc (alloc_size);
|
||||
memcpy (buf->data, data, data_size);
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Free the data in a buffer. Does *not* free
|
||||
* the buffer object itself.
|
||||
*
|
||||
* @param buf buffer to de-initialize
|
||||
*/
|
||||
static void
|
||||
buffer_deinit (struct Buffer *buf)
|
||||
{
|
||||
GNUNET_free (buf->data);
|
||||
buf->data = NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Append data to a buffer, growing the buffer if necessary.
|
||||
*
|
||||
* @param buf the buffer to append to
|
||||
* @param data the data to append
|
||||
* @param size the size of @a data
|
||||
* @param max_size maximum size that the buffer can grow to
|
||||
* @return GNUNET_OK on success,
|
||||
* GNUNET_NO if the buffer can't accomodate for the new data
|
||||
* GNUNET_SYSERR on fatal error (out of memory?)
|
||||
*/
|
||||
static int
|
||||
buffer_append (struct Buffer *buf, const void *data, size_t data_size, size_t max_size)
|
||||
{
|
||||
if (buf->fill + data_size > max_size)
|
||||
return GNUNET_NO;
|
||||
if (data_size + buf->fill > buf->alloc)
|
||||
{
|
||||
char *new_buf;
|
||||
size_t new_size = buf->alloc;
|
||||
while (new_size < buf->fill + data_size)
|
||||
new_size += 2;
|
||||
if (new_size > max_size)
|
||||
return GNUNET_NO;
|
||||
new_buf = GNUNET_malloc (new_size);
|
||||
memcpy (new_buf, buf->data, buf->fill);
|
||||
buf->data = new_buf;
|
||||
buf->alloc = new_size;
|
||||
}
|
||||
memcpy (buf->data + buf->fill, data, data_size);
|
||||
buf->fill += data_size;
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send JSON object as response. Decreases the reference count of the
|
||||
* JSON object.
|
||||
*
|
||||
* @param connection the MHD connection
|
||||
* @param json the json object
|
||||
* @param status_code the http status code
|
||||
* @return MHD result code
|
||||
*/
|
||||
int
|
||||
send_response_json (struct MHD_Connection *connection,
|
||||
json_t *json,
|
||||
unsigned int status_code)
|
||||
{
|
||||
struct MHD_Response *resp;
|
||||
char *json_str;
|
||||
|
||||
json_str = json_dumps (json, JSON_INDENT(2));
|
||||
json_decref (json);
|
||||
resp = MHD_create_response_from_buffer (strlen (json_str), json_str,
|
||||
MHD_RESPMEM_MUST_FREE);
|
||||
if (NULL == resp)
|
||||
return MHD_NO;
|
||||
return MHD_queue_response (connection, status_code, resp);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send a JSON object via an MHD connection,
|
||||
* specified with the JANSSON pack syntax (see json_pack).
|
||||
*
|
||||
* @param connection connection to send the JSON over
|
||||
* @param http_code HTTP status for the response
|
||||
* @param fmt format string for pack
|
||||
* @param ... varargs
|
||||
* @return MHD_YES on success or MHD_NO on error
|
||||
*/
|
||||
int
|
||||
request_send_json_pack (struct MHD_Connection *connection,
|
||||
unsigned int http_code,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
json_t *msg;
|
||||
va_list argp;
|
||||
int ret;
|
||||
|
||||
va_start(argp, fmt);
|
||||
msg = json_vpack_ex (NULL, 0, fmt, argp);
|
||||
va_end(argp);
|
||||
if (NULL == msg)
|
||||
return MHD_NO;
|
||||
ret = send_response_json (connection, msg, http_code);
|
||||
json_decref (msg);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Process a POST request containing a JSON object.
|
||||
*
|
||||
* @param connection the MHD connection
|
||||
* @param con_cs the closure (contains a 'struct Buffer *')
|
||||
* @param upload_data the POST data
|
||||
* @param upload_data_size the POST data size
|
||||
* @param json the JSON object for a completed request
|
||||
*
|
||||
* @returns
|
||||
* GNUNET_YES if json object was parsed
|
||||
* GNUNET_NO is request incomplete or invalid
|
||||
* GNUNET_SYSERR on internal error
|
||||
*/
|
||||
int
|
||||
process_post_json (struct MHD_Connection *connection,
|
||||
void **con_cls,
|
||||
const char *upload_data,
|
||||
size_t *upload_data_size,
|
||||
json_t **json)
|
||||
{
|
||||
struct Buffer *r = *con_cls;
|
||||
|
||||
if (NULL == *con_cls)
|
||||
{
|
||||
/* We are seeing a fresh POST request. */
|
||||
|
||||
r = GNUNET_new (struct Buffer);
|
||||
if (GNUNET_OK != buffer_init (r, upload_data, *upload_data_size,
|
||||
REQUEST_BUFFER_INITIAL, REQUEST_BUFFER_MAX))
|
||||
{
|
||||
*con_cls = NULL;
|
||||
buffer_deinit (r);
|
||||
GNUNET_free (r);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
*upload_data_size = 0;
|
||||
*con_cls = r;
|
||||
return GNUNET_NO;
|
||||
}
|
||||
if (0 != *upload_data_size)
|
||||
{
|
||||
/* We are seeing an old request with more data available. */
|
||||
|
||||
if (GNUNET_OK != buffer_append (r, upload_data, *upload_data_size,
|
||||
REQUEST_BUFFER_MAX))
|
||||
{
|
||||
/* Request too long or we're out of memory. */
|
||||
|
||||
*con_cls = NULL;
|
||||
buffer_deinit (r);
|
||||
GNUNET_free (r);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
*upload_data_size = 0;
|
||||
return GNUNET_NO;
|
||||
}
|
||||
|
||||
/* We have seen the whole request. */
|
||||
|
||||
*json = json_loadb (r->data, r->fill, 0, NULL);
|
||||
buffer_deinit (r);
|
||||
GNUNET_free (r);
|
||||
if (NULL == *json)
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Can't parse JSON request body\n");
|
||||
return request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST,
|
||||
GNUNET_NO, GNUNET_SYSERR,
|
||||
"{s:s}",
|
||||
"error", "invalid json");
|
||||
}
|
||||
*con_cls = NULL;
|
||||
|
||||
return GNUNET_YES;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Navigate through a JSON tree.
|
||||
*
|
||||
* Sends an error response if navigation is impossible (i.e.
|
||||
* the JSON object is invalid)
|
||||
*
|
||||
* @param connection the connection to send an error response to
|
||||
* @param root the JSON node to start the navigation at.
|
||||
* @param ... navigation specification (see JNAV_*)
|
||||
* @return GNUNET_YES if navigation was successful
|
||||
* GNUNET_NO if json is malformed, error response was generated
|
||||
* GNUNET_SYSERR on internal error
|
||||
*/
|
||||
int
|
||||
request_json_require_nav (struct MHD_Connection *connection,
|
||||
const json_t *root, ...)
|
||||
{
|
||||
va_list argp;
|
||||
int ignore = GNUNET_NO;
|
||||
// what's our current path from 'root'?
|
||||
json_t *path;
|
||||
|
||||
path = json_array ();
|
||||
|
||||
va_start(argp, root);
|
||||
|
||||
while (1)
|
||||
{
|
||||
int command = va_arg(argp, int);
|
||||
switch (command)
|
||||
{
|
||||
case JNAV_FIELD:
|
||||
{
|
||||
const char *fname = va_arg(argp, const char *);
|
||||
if (GNUNET_YES == ignore)
|
||||
break;
|
||||
json_array_append_new (path, json_string (fname));
|
||||
root = json_object_get (root, fname);
|
||||
if (NULL == root)
|
||||
{
|
||||
|
||||
(void) request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST,
|
||||
0, 0,
|
||||
"{s:s,s:o}",
|
||||
"error", "missing field in JSON",
|
||||
"path", path);
|
||||
ignore = GNUNET_YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case JNAV_INDEX:
|
||||
{
|
||||
int fnum = va_arg(argp, int);
|
||||
if (GNUNET_YES == ignore)
|
||||
break;
|
||||
json_array_append_new (path, json_integer (fnum));
|
||||
root = json_array_get (root, fnum);
|
||||
if (NULL == root)
|
||||
{
|
||||
(void) request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST,
|
||||
0, 0,
|
||||
"{s:s, s:o}",
|
||||
"error", "missing index in JSON",
|
||||
"path", path);
|
||||
ignore = GNUNET_YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case JNAV_RET_DATA:
|
||||
{
|
||||
void *where = va_arg (argp, void *);
|
||||
size_t len = va_arg (argp, size_t);
|
||||
const char *str;
|
||||
int res;
|
||||
|
||||
va_end(argp);
|
||||
if (GNUNET_YES == ignore)
|
||||
return GNUNET_NO;
|
||||
str = json_string_value (root);
|
||||
if (NULL == str)
|
||||
{
|
||||
(void) request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST,
|
||||
0, 0,
|
||||
"{s:s, s:o}",
|
||||
"error", "string expected",
|
||||
"path", path);
|
||||
return GNUNET_NO;
|
||||
}
|
||||
res = GNUNET_STRINGS_string_to_data (str, strlen (str),
|
||||
where, len);
|
||||
if (GNUNET_OK != res)
|
||||
{
|
||||
(void) request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST,
|
||||
0, 0,
|
||||
"{s:s,s:o}",
|
||||
"error", "malformed binary data in JSON",
|
||||
"path", path);
|
||||
return GNUNET_NO;
|
||||
}
|
||||
return GNUNET_YES;
|
||||
}
|
||||
break;
|
||||
case JNAV_RET_DATA_VAR:
|
||||
{
|
||||
void **where = va_arg (argp, void **);
|
||||
size_t *len = va_arg (argp, size_t *);
|
||||
const char *str;
|
||||
|
||||
va_end(argp);
|
||||
if (GNUNET_YES == ignore)
|
||||
return GNUNET_NO;
|
||||
str = json_string_value (root);
|
||||
if (NULL == str)
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
*len = (strlen (str) * 5) / 8;
|
||||
if (where != NULL)
|
||||
{
|
||||
int res;
|
||||
*where = GNUNET_malloc (*len);
|
||||
res = GNUNET_STRINGS_string_to_data (str, strlen (str),
|
||||
*where, *len);
|
||||
if (GNUNET_OK != res)
|
||||
{
|
||||
(void) request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST,
|
||||
0, 0,
|
||||
"{s:s, s:o}",
|
||||
"error", "malformed binary data in JSON",
|
||||
"path", path);
|
||||
return GNUNET_NO;
|
||||
}
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
break;
|
||||
case JNAV_RET_TYPED_JSON:
|
||||
{
|
||||
int typ = va_arg (argp, int);
|
||||
const json_t **r_json = va_arg (argp, const json_t **);
|
||||
|
||||
va_end(argp);
|
||||
if (GNUNET_YES == ignore)
|
||||
return GNUNET_NO;
|
||||
if (typ != -1 && json_typeof (root) != typ)
|
||||
{
|
||||
(void) request_send_json_pack (connection, MHD_HTTP_BAD_REQUEST,
|
||||
0, 0,
|
||||
"{s:s, s:i, s:i s:o}",
|
||||
"error", "wrong JSON field type",
|
||||
"type_expected", typ,
|
||||
"type_actual", json_typeof (root),
|
||||
"path", path);
|
||||
return GNUNET_NO;
|
||||
}
|
||||
*r_json = root;
|
||||
return GNUNET_OK;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
GNUNET_assert (0);
|
||||
}
|
||||
}
|
||||
GNUNET_assert (0);
|
||||
}
|
||||
|
||||
|
||||
|
28
src/util/misc.supp
Normal file
28
src/util/misc.supp
Normal file
@ -0,0 +1,28 @@
|
||||
{
|
||||
<gnunet_gcrypt_init>
|
||||
Memcheck:Leak
|
||||
match-leak-kinds:reachable
|
||||
...
|
||||
fun:GNUNET_CRYPTO_random_init
|
||||
fun:call_init.part.0
|
||||
...
|
||||
}
|
||||
|
||||
{
|
||||
<mpi_ec_new>
|
||||
Memcheck:Leak
|
||||
match-leak-kinds:reachable
|
||||
...
|
||||
fun:point_from_keyparam
|
||||
fun:_gcry_mpi_ec_new
|
||||
...
|
||||
}
|
||||
|
||||
{
|
||||
<gnunet_log_setup>
|
||||
Memcheck:Leak
|
||||
match-leak-kinds:reachable
|
||||
...
|
||||
fun:GNUNET_log_setup
|
||||
...
|
||||
}
|
925
src/util/rsa.c
Normal file
925
src/util/rsa.c
Normal file
@ -0,0 +1,925 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file util/rsa.c
|
||||
* @brief RSA key management utilities. Most of the code here is taken from
|
||||
* gnunet-0.9.5a
|
||||
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||
*
|
||||
* Authors of the gnunet code:
|
||||
* Christian Grothoff
|
||||
* Krista Bennett
|
||||
* Gerd Knorr <kraxel@bytesex.org>
|
||||
* Ioana Patrascu
|
||||
* Tzvetan Horozov
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#include "gcrypt.h"
|
||||
#include "gnunet/gnunet_util_lib.h"
|
||||
#include "taler_rsa.h"
|
||||
|
||||
|
||||
|
||||
#define LOG(kind,...) GNUNET_log_from (kind, "util", __VA_ARGS__)
|
||||
|
||||
#define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util", syscall)
|
||||
|
||||
#define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
|
||||
|
||||
/**
|
||||
* Log an error message at log-level 'level' that indicates
|
||||
* a failure of the command 'cmd' with the message given
|
||||
* by gcry_strerror(rc).
|
||||
*/
|
||||
#define LOG_GCRY(level, cmd, rc) do { LOG(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, gcry_strerror(rc)); } while(0)
|
||||
|
||||
/**
|
||||
* Shorthand to cleanup non null mpi data types
|
||||
*/
|
||||
#define mpi_release_non_null(mpi) \
|
||||
if (NULL != mpi) gcry_mpi_release (mpi);
|
||||
|
||||
/**
|
||||
* The private information of an RSA key pair.
|
||||
* NOTE: this must match the definition in crypto_ksk.c and gnunet-rsa.c!
|
||||
*/
|
||||
struct TALER_RSA_PrivateKey
|
||||
{
|
||||
/**
|
||||
* Libgcrypt S-expression for the ECC key.
|
||||
*/
|
||||
gcry_sexp_t sexp;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Extract values from an S-expression.
|
||||
*
|
||||
* @param array where to store the result(s)
|
||||
* @param sexp S-expression to parse
|
||||
* @param topname top-level name in the S-expression that is of interest
|
||||
* @param elems names of the elements to extract
|
||||
* @return 0 on success
|
||||
*/
|
||||
static int
|
||||
key_from_sexp (gcry_mpi_t * array, gcry_sexp_t sexp, const char *topname,
|
||||
const char *elems)
|
||||
{
|
||||
gcry_sexp_t list;
|
||||
gcry_sexp_t l2;
|
||||
const char *s;
|
||||
unsigned int i;
|
||||
unsigned int idx;
|
||||
|
||||
if (! (list = gcry_sexp_find_token (sexp, topname, 0)))
|
||||
return 1;
|
||||
l2 = gcry_sexp_cadr (list);
|
||||
gcry_sexp_release (list);
|
||||
list = l2;
|
||||
if (! list)
|
||||
return 2;
|
||||
idx = 0;
|
||||
for (s = elems; *s; s++, idx++)
|
||||
{
|
||||
if (! (l2 = gcry_sexp_find_token (list, s, 1)))
|
||||
{
|
||||
for (i = 0; i < idx; i++)
|
||||
{
|
||||
gcry_free (array[i]);
|
||||
array[i] = NULL;
|
||||
}
|
||||
gcry_sexp_release (list);
|
||||
return 3; /* required parameter not found */
|
||||
}
|
||||
array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
|
||||
gcry_sexp_release (l2);
|
||||
if (! array[idx])
|
||||
{
|
||||
for (i = 0; i < idx; i++)
|
||||
{
|
||||
gcry_free (array[i]);
|
||||
array[i] = NULL;
|
||||
}
|
||||
gcry_sexp_release (list);
|
||||
return 4; /* required parameter is invalid */
|
||||
}
|
||||
}
|
||||
gcry_sexp_release (list);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* If target != size, move target bytes to the
|
||||
* end of the size-sized buffer and zero out the
|
||||
* first target-size bytes.
|
||||
*
|
||||
* @param buf original buffer
|
||||
* @param size number of bytes in the buffer
|
||||
* @param target target size of the buffer
|
||||
*/
|
||||
static void
|
||||
adjust (unsigned char *buf, size_t size, size_t target)
|
||||
{
|
||||
if (size < target)
|
||||
{
|
||||
memmove (&buf[target - size], buf, size);
|
||||
memset (buf, 0, target - size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new private key. Caller must free return value.
|
||||
*
|
||||
* @return fresh private key
|
||||
*/
|
||||
struct TALER_RSA_PrivateKey *
|
||||
TALER_RSA_key_create ()
|
||||
{
|
||||
struct TALER_RSA_PrivateKey *ret;
|
||||
gcry_sexp_t s_key;
|
||||
gcry_sexp_t s_keyparam;
|
||||
|
||||
GNUNET_assert (0 ==
|
||||
gcry_sexp_build (&s_keyparam, NULL,
|
||||
"(genkey(rsa(nbits %d)(rsa-use-e 3:257)))",
|
||||
2048));
|
||||
GNUNET_assert (0 == gcry_pk_genkey (&s_key, s_keyparam));
|
||||
gcry_sexp_release (s_keyparam);
|
||||
#if EXTRA_CHECKS
|
||||
GNUNET_assert (0 == gcry_pk_testkey (s_key));
|
||||
#endif
|
||||
ret = GNUNET_malloc (sizeof (struct TALER_RSA_PrivateKey));
|
||||
ret->sexp = s_key;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Free memory occupied by the private key.
|
||||
*
|
||||
* @param key pointer to the memory to free
|
||||
*/
|
||||
void
|
||||
TALER_RSA_key_free (struct TALER_RSA_PrivateKey *key)
|
||||
{
|
||||
gcry_sexp_release (key->sexp);
|
||||
GNUNET_free (key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encode the private key in a format suitable for
|
||||
* storing it into a file.
|
||||
* @return encoding of the private key
|
||||
*/
|
||||
struct TALER_RSA_PrivateKeyBinaryEncoded *
|
||||
TALER_RSA_encode_key (const struct TALER_RSA_PrivateKey *hostkey)
|
||||
{
|
||||
struct TALER_RSA_PrivateKeyBinaryEncoded *retval;
|
||||
gcry_mpi_t pkv[6];
|
||||
void *pbu[6];
|
||||
size_t sizes[6];
|
||||
int rc;
|
||||
int i;
|
||||
int size;
|
||||
|
||||
#if EXTRA_CHECKS
|
||||
if (gcry_pk_testkey (hostkey->sexp))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
memset (pkv, 0, sizeof (gcry_mpi_t) * 6);
|
||||
rc = key_from_sexp (pkv, hostkey->sexp, "private-key", "nedpqu");
|
||||
if (rc)
|
||||
rc = key_from_sexp (pkv, hostkey->sexp, "rsa", "nedpqu");
|
||||
if (rc)
|
||||
rc = key_from_sexp (pkv, hostkey->sexp, "private-key", "nedpq");
|
||||
if (rc)
|
||||
rc = key_from_sexp (pkv, hostkey->sexp, "rsa", "nedpq");
|
||||
if (rc)
|
||||
rc = key_from_sexp (pkv, hostkey->sexp, "private-key", "ned");
|
||||
if (rc)
|
||||
rc = key_from_sexp (pkv, hostkey->sexp, "rsa", "ned");
|
||||
GNUNET_assert (0 == rc);
|
||||
size = sizeof (struct TALER_RSA_PrivateKeyBinaryEncoded);
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
if (NULL != pkv[i])
|
||||
{
|
||||
GNUNET_assert (0 ==
|
||||
gcry_mpi_aprint (GCRYMPI_FMT_USG,
|
||||
(unsigned char **) &pbu[i], &sizes[i],
|
||||
pkv[i]));
|
||||
size += sizes[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
pbu[i] = NULL;
|
||||
sizes[i] = 0;
|
||||
}
|
||||
}
|
||||
GNUNET_assert (size < 65536);
|
||||
retval = GNUNET_malloc (size);
|
||||
retval->len = htons (size);
|
||||
i = 0;
|
||||
retval->sizen = htons (sizes[0]);
|
||||
memcpy (&((char *) (&retval[1]))[i], pbu[0], sizes[0]);
|
||||
i += sizes[0];
|
||||
retval->sizee = htons (sizes[1]);
|
||||
memcpy (&((char *) (&retval[1]))[i], pbu[1], sizes[1]);
|
||||
i += sizes[1];
|
||||
retval->sized = htons (sizes[2]);
|
||||
memcpy (&((char *) (&retval[1]))[i], pbu[2], sizes[2]);
|
||||
i += sizes[2];
|
||||
/* swap p and q! */
|
||||
retval->sizep = htons (sizes[4]);
|
||||
memcpy (&((char *) (&retval[1]))[i], pbu[4], sizes[4]);
|
||||
i += sizes[4];
|
||||
retval->sizeq = htons (sizes[3]);
|
||||
memcpy (&((char *) (&retval[1]))[i], pbu[3], sizes[3]);
|
||||
i += sizes[3];
|
||||
retval->sizedmp1 = htons (0);
|
||||
retval->sizedmq1 = htons (0);
|
||||
memcpy (&((char *) (&retval[1]))[i], pbu[5], sizes[5]);
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
if (pkv[i] != NULL)
|
||||
gcry_mpi_release (pkv[i]);
|
||||
if (pbu[i] != NULL)
|
||||
free (pbu[i]);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract the public key of the given private key.
|
||||
*
|
||||
* @param priv the private key
|
||||
* @param pub where to write the public key
|
||||
*/
|
||||
void
|
||||
TALER_RSA_key_get_public (const struct TALER_RSA_PrivateKey *priv,
|
||||
struct TALER_RSA_PublicKeyBinaryEncoded *pub)
|
||||
{
|
||||
gcry_mpi_t skey[2];
|
||||
size_t size;
|
||||
int rc;
|
||||
|
||||
rc = key_from_sexp (skey, priv->sexp, "public-key", "ne");
|
||||
if (0 != rc)
|
||||
rc = key_from_sexp (skey, priv->sexp, "private-key", "ne");
|
||||
if (0 != rc)
|
||||
rc = key_from_sexp (skey, priv->sexp, "rsa", "ne");
|
||||
GNUNET_assert (0 == rc);
|
||||
pub->len =
|
||||
htons (sizeof (struct TALER_RSA_PublicKeyBinaryEncoded) -
|
||||
sizeof (pub->padding));
|
||||
pub->sizen = htons (TALER_RSA_DATA_ENCODING_LENGTH);
|
||||
pub->padding = 0;
|
||||
size = TALER_RSA_DATA_ENCODING_LENGTH;
|
||||
GNUNET_assert (0 ==
|
||||
gcry_mpi_print (GCRYMPI_FMT_USG, &pub->key[0], size, &size,
|
||||
skey[0]));
|
||||
adjust (&pub->key[0], size, TALER_RSA_DATA_ENCODING_LENGTH);
|
||||
size = TALER_RSA_KEY_LENGTH - TALER_RSA_DATA_ENCODING_LENGTH;
|
||||
GNUNET_assert (0 ==
|
||||
gcry_mpi_print (GCRYMPI_FMT_USG,
|
||||
&pub->key
|
||||
[TALER_RSA_DATA_ENCODING_LENGTH], size,
|
||||
&size, skey[1]));
|
||||
adjust (&pub->key[TALER_RSA_DATA_ENCODING_LENGTH], size,
|
||||
TALER_RSA_KEY_LENGTH -
|
||||
TALER_RSA_DATA_ENCODING_LENGTH);
|
||||
gcry_mpi_release (skey[0]);
|
||||
gcry_mpi_release (skey[1]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decode the private key from the data-format back
|
||||
* to the "normal", internal format.
|
||||
*
|
||||
* @param buf the buffer where the private key data is stored
|
||||
* @param len the length of the data in 'buffer'
|
||||
* @return NULL on error
|
||||
*/
|
||||
struct TALER_RSA_PrivateKey *
|
||||
TALER_RSA_decode_key (const char *buf, uint16_t len)
|
||||
{
|
||||
struct TALER_RSA_PrivateKey *ret;
|
||||
const struct TALER_RSA_PrivateKeyBinaryEncoded *encoding =
|
||||
(const struct TALER_RSA_PrivateKeyBinaryEncoded *) buf;
|
||||
gcry_sexp_t res;
|
||||
gcry_mpi_t n;
|
||||
gcry_mpi_t e;
|
||||
gcry_mpi_t d;
|
||||
gcry_mpi_t p;
|
||||
gcry_mpi_t q;
|
||||
gcry_mpi_t u;
|
||||
int rc;
|
||||
size_t size;
|
||||
size_t pos;
|
||||
uint16_t enc_len;
|
||||
size_t erroff;
|
||||
|
||||
enc_len = ntohs (encoding->len);
|
||||
if (len != enc_len)
|
||||
return NULL;
|
||||
|
||||
pos = 0;
|
||||
size = ntohs (encoding->sizen);
|
||||
rc = gcry_mpi_scan (&n, GCRYMPI_FMT_USG,
|
||||
&((const unsigned char *) (&encoding[1]))[pos], size,
|
||||
&size);
|
||||
pos += ntohs (encoding->sizen);
|
||||
if (0 != rc)
|
||||
{
|
||||
LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
|
||||
return NULL;
|
||||
}
|
||||
size = ntohs (encoding->sizee);
|
||||
rc = gcry_mpi_scan (&e, GCRYMPI_FMT_USG,
|
||||
&((const unsigned char *) (&encoding[1]))[pos], size,
|
||||
&size);
|
||||
pos += ntohs (encoding->sizee);
|
||||
if (0 != rc)
|
||||
{
|
||||
LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
|
||||
gcry_mpi_release (n);
|
||||
return NULL;
|
||||
}
|
||||
size = ntohs (encoding->sized);
|
||||
rc = gcry_mpi_scan (&d, GCRYMPI_FMT_USG,
|
||||
&((const unsigned char *) (&encoding[1]))[pos], size,
|
||||
&size);
|
||||
pos += ntohs (encoding->sized);
|
||||
if (0 != rc)
|
||||
{
|
||||
LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
|
||||
gcry_mpi_release (n);
|
||||
gcry_mpi_release (e);
|
||||
return NULL;
|
||||
}
|
||||
/* swap p and q! */
|
||||
size = ntohs (encoding->sizep);
|
||||
if (size > 0)
|
||||
{
|
||||
rc = gcry_mpi_scan (&q, GCRYMPI_FMT_USG,
|
||||
&((const unsigned char *) (&encoding[1]))[pos], size,
|
||||
&size);
|
||||
pos += ntohs (encoding->sizep);
|
||||
if (0 != rc)
|
||||
{
|
||||
LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
|
||||
gcry_mpi_release (n);
|
||||
gcry_mpi_release (e);
|
||||
gcry_mpi_release (d);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
q = NULL;
|
||||
size = ntohs (encoding->sizeq);
|
||||
if (size > 0)
|
||||
{
|
||||
rc = gcry_mpi_scan (&p, GCRYMPI_FMT_USG,
|
||||
&((const unsigned char *) (&encoding[1]))[pos], size,
|
||||
&size);
|
||||
pos += ntohs (encoding->sizeq);
|
||||
if (0 != rc)
|
||||
{
|
||||
LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
|
||||
gcry_mpi_release (n);
|
||||
gcry_mpi_release (e);
|
||||
gcry_mpi_release (d);
|
||||
if (NULL != q)
|
||||
gcry_mpi_release (q);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
p = NULL;
|
||||
pos += ntohs (encoding->sizedmp1);
|
||||
pos += ntohs (encoding->sizedmq1);
|
||||
size =
|
||||
ntohs (encoding->len) - sizeof (struct TALER_RSA_PrivateKeyBinaryEncoded) - pos;
|
||||
if (size > 0)
|
||||
{
|
||||
rc = gcry_mpi_scan (&u, GCRYMPI_FMT_USG,
|
||||
&((const unsigned char *) (&encoding[1]))[pos], size,
|
||||
&size);
|
||||
if (0 != rc)
|
||||
{
|
||||
LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
|
||||
gcry_mpi_release (n);
|
||||
gcry_mpi_release (e);
|
||||
gcry_mpi_release (d);
|
||||
if (NULL != p)
|
||||
gcry_mpi_release (p);
|
||||
if (NULL != q)
|
||||
gcry_mpi_release (q);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
u = NULL;
|
||||
|
||||
if ((NULL != p) && (NULL != q) && (NULL != u))
|
||||
{
|
||||
rc = gcry_sexp_build (&res, &erroff,
|
||||
"(private-key(rsa(n %m)(e %m)(d %m)(p %m)(q %m)(u %m)))",
|
||||
n, e, d, p, q, u);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((NULL != p) && (NULL != q))
|
||||
{
|
||||
rc = gcry_sexp_build (&res, &erroff,
|
||||
"(private-key(rsa(n %m)(e %m)(d %m)(p %m)(q %m)))",
|
||||
n, e, d, p, q);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = gcry_sexp_build (&res, &erroff,
|
||||
"(private-key(rsa(n %m)(e %m)(d %m)))", n, e, d);
|
||||
}
|
||||
}
|
||||
gcry_mpi_release (n);
|
||||
gcry_mpi_release (e);
|
||||
gcry_mpi_release (d);
|
||||
if (NULL != p)
|
||||
gcry_mpi_release (p);
|
||||
if (NULL != q)
|
||||
gcry_mpi_release (q);
|
||||
if (NULL != u)
|
||||
gcry_mpi_release (u);
|
||||
|
||||
if (0 != rc)
|
||||
LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc);
|
||||
if (0 != (rc = gcry_pk_testkey (res)))
|
||||
{
|
||||
LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_pk_testkey", rc);
|
||||
return NULL;
|
||||
}
|
||||
ret = GNUNET_malloc (sizeof (struct TALER_RSA_PrivateKey));
|
||||
ret->sexp = res;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a public key to a string.
|
||||
*
|
||||
* @param pub key to convert
|
||||
* @return string representing 'pub'
|
||||
*/
|
||||
char *
|
||||
TALER_RSA_public_key_to_string (const struct TALER_RSA_PublicKeyBinaryEncoded *pub)
|
||||
{
|
||||
char *pubkeybuf;
|
||||
size_t keylen = (sizeof (struct TALER_RSA_PublicKeyBinaryEncoded)) * 8;
|
||||
char *end;
|
||||
|
||||
if (keylen % 5 > 0)
|
||||
keylen += 5 - keylen % 5;
|
||||
keylen /= 5;
|
||||
pubkeybuf = GNUNET_malloc (keylen + 1);
|
||||
end = GNUNET_STRINGS_data_to_string ((unsigned char *) pub,
|
||||
sizeof (struct TALER_RSA_PublicKeyBinaryEncoded),
|
||||
pubkeybuf,
|
||||
keylen);
|
||||
if (NULL == end)
|
||||
{
|
||||
GNUNET_free (pubkeybuf);
|
||||
return NULL;
|
||||
}
|
||||
*end = '\0';
|
||||
return pubkeybuf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a string representing a public key to a public key.
|
||||
*
|
||||
* @param enc encoded public key
|
||||
* @param enclen number of bytes in enc (without 0-terminator)
|
||||
* @param pub where to store the public key
|
||||
* @return GNUNET_OK on success
|
||||
*/
|
||||
int
|
||||
TALER_RSA_public_key_from_string (const char *enc,
|
||||
size_t enclen,
|
||||
struct TALER_RSA_PublicKeyBinaryEncoded *pub)
|
||||
{
|
||||
size_t keylen = (sizeof (struct TALER_RSA_PublicKeyBinaryEncoded)) * 8;
|
||||
|
||||
if (keylen % 5 > 0)
|
||||
keylen += 5 - keylen % 5;
|
||||
keylen /= 5;
|
||||
if (enclen != keylen)
|
||||
return GNUNET_SYSERR;
|
||||
|
||||
if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, enclen,
|
||||
(unsigned char*) pub,
|
||||
sizeof (struct TALER_RSA_PublicKeyBinaryEncoded)))
|
||||
return GNUNET_SYSERR;
|
||||
if ( (ntohs (pub->len) != sizeof (struct TALER_RSA_PublicKeyBinaryEncoded)) ||
|
||||
(ntohs (pub->padding) != 0) ||
|
||||
(ntohs (pub->sizen) != TALER_RSA_DATA_ENCODING_LENGTH) )
|
||||
return GNUNET_SYSERR;
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert the data specified in the given purpose argument to an
|
||||
* S-expression suitable for signature operations.
|
||||
*
|
||||
* @param ptr pointer to the data to convert
|
||||
* @param size the size of the data
|
||||
* @return converted s-expression
|
||||
*/
|
||||
static gcry_sexp_t
|
||||
data_to_sexp (const void *ptr, size_t size)
|
||||
{
|
||||
gcry_mpi_t value;
|
||||
gcry_sexp_t data;
|
||||
|
||||
value = NULL;
|
||||
data = NULL;
|
||||
GNUNET_assert (0 == gcry_mpi_scan (&value, GCRYMPI_FMT_USG, ptr, size, NULL));
|
||||
GNUNET_assert (0 == gcry_sexp_build (&data, NULL, "(data (flags raw) (value %M))", value));
|
||||
gcry_mpi_release (value);
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sign the given hash block.
|
||||
*
|
||||
* @param key private key to use for the signing
|
||||
* @param hash the block containing the hash of the message to sign
|
||||
* @param hash_size the size of the hash block
|
||||
* @param sig where to write the signature
|
||||
* @return GNUNET_SYSERR on error, GNUNET_OK on success
|
||||
*/
|
||||
int
|
||||
TALER_RSA_sign (const struct TALER_RSA_PrivateKey *key,
|
||||
const void *hash,
|
||||
size_t hash_size,
|
||||
struct TALER_RSA_Signature *sig)
|
||||
{
|
||||
gcry_sexp_t result;
|
||||
gcry_sexp_t data;
|
||||
size_t ssize;
|
||||
gcry_mpi_t rval;
|
||||
|
||||
data = data_to_sexp (hash, hash_size);
|
||||
GNUNET_assert (0 == gcry_pk_sign (&result, data, key->sexp));
|
||||
gcry_sexp_release (data);
|
||||
GNUNET_assert (0 == key_from_sexp (&rval, result, "rsa", "s"));
|
||||
gcry_sexp_release (result);
|
||||
ssize = sizeof (struct TALER_RSA_Signature);
|
||||
GNUNET_assert (0 ==
|
||||
gcry_mpi_print (GCRYMPI_FMT_USG, (unsigned char *) sig, ssize,
|
||||
&ssize, rval));
|
||||
gcry_mpi_release (rval);
|
||||
adjust (sig->sig, ssize, sizeof (struct TALER_RSA_Signature));
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert the given public key from the network format to the
|
||||
* S-expression that can be used by libgcrypt.
|
||||
*
|
||||
* @param publicKey public key to decode
|
||||
* @return NULL on error
|
||||
*/
|
||||
static gcry_sexp_t
|
||||
decode_public_key (const struct TALER_RSA_PublicKeyBinaryEncoded *publicKey)
|
||||
{
|
||||
gcry_sexp_t result;
|
||||
gcry_mpi_t n;
|
||||
gcry_mpi_t e;
|
||||
size_t size;
|
||||
size_t erroff;
|
||||
int rc;
|
||||
|
||||
if ((ntohs (publicKey->sizen) != TALER_RSA_DATA_ENCODING_LENGTH) ||
|
||||
(ntohs (publicKey->len) !=
|
||||
sizeof (struct TALER_RSA_PublicKeyBinaryEncoded) -
|
||||
sizeof (publicKey->padding)))
|
||||
{
|
||||
GNUNET_break (0);
|
||||
return NULL;
|
||||
}
|
||||
size = TALER_RSA_DATA_ENCODING_LENGTH;
|
||||
if (0 != (rc = gcry_mpi_scan (&n, GCRYMPI_FMT_USG, &publicKey->key[0], size, &size)))
|
||||
{
|
||||
LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
|
||||
return NULL;
|
||||
}
|
||||
size = TALER_RSA_KEY_LENGTH - TALER_RSA_DATA_ENCODING_LENGTH;
|
||||
if (0 != (rc = gcry_mpi_scan (&e, GCRYMPI_FMT_USG,
|
||||
&publicKey->key[TALER_RSA_DATA_ENCODING_LENGTH],
|
||||
size, &size)))
|
||||
{
|
||||
LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
|
||||
gcry_mpi_release (n);
|
||||
return NULL;
|
||||
}
|
||||
rc = gcry_sexp_build (&result, &erroff, "(public-key(rsa(n %m)(e %m)))", n,
|
||||
e);
|
||||
gcry_mpi_release (n);
|
||||
gcry_mpi_release (e);
|
||||
if (0 != rc)
|
||||
{
|
||||
LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_sexp_build", rc); /* erroff gives more info */
|
||||
return NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Verify signature with the given hash.
|
||||
*
|
||||
* @param hash the hash code to verify against the signature
|
||||
* @param sig signature that is being validated
|
||||
* @param publicKey public key of the signer
|
||||
* @returns GNUNET_OK if ok, GNUNET_SYSERR if invalid
|
||||
*/
|
||||
int
|
||||
TALER_RSA_hash_verify (const struct GNUNET_HashCode *hash,
|
||||
const struct TALER_RSA_Signature *sig,
|
||||
const struct TALER_RSA_PublicKeyBinaryEncoded *publicKey)
|
||||
{
|
||||
gcry_sexp_t data;
|
||||
gcry_sexp_t sigdata;
|
||||
size_t size;
|
||||
gcry_mpi_t val;
|
||||
gcry_sexp_t psexp;
|
||||
size_t erroff;
|
||||
int rc;
|
||||
|
||||
size = sizeof (struct TALER_RSA_Signature);
|
||||
GNUNET_assert (0 ==
|
||||
gcry_mpi_scan (&val, GCRYMPI_FMT_USG,
|
||||
(const unsigned char *) sig, size, &size));
|
||||
GNUNET_assert (0 ==
|
||||
gcry_sexp_build (&sigdata, &erroff, "(sig-val(rsa(s %m)))",
|
||||
val));
|
||||
gcry_mpi_release (val);
|
||||
data = data_to_sexp (hash, sizeof (struct GNUNET_HashCode));
|
||||
if (! (psexp = decode_public_key (publicKey)))
|
||||
{
|
||||
gcry_sexp_release (data);
|
||||
gcry_sexp_release (sigdata);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
rc = gcry_pk_verify (sigdata, data, psexp);
|
||||
gcry_sexp_release (psexp);
|
||||
gcry_sexp_release (data);
|
||||
gcry_sexp_release (sigdata);
|
||||
if (rc)
|
||||
{
|
||||
LOG (GNUNET_ERROR_TYPE_WARNING,
|
||||
_("RSA signature verification failed at %s:%d: %s\n"), __FILE__,
|
||||
__LINE__, gcry_strerror (rc));
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Verify signature on the given message
|
||||
*
|
||||
* @param msg the message
|
||||
* @param size the size of the message
|
||||
* @param sig signature that is being validated
|
||||
* @param publicKey public key of the signer
|
||||
* @returns GNUNET_OK if ok, GNUNET_SYSERR if invalid
|
||||
*/
|
||||
int
|
||||
TALER_RSA_verify (const void *msg, size_t size,
|
||||
const struct TALER_RSA_Signature *sig,
|
||||
const struct TALER_RSA_PublicKeyBinaryEncoded *publicKey)
|
||||
{
|
||||
struct GNUNET_HashCode hash;
|
||||
|
||||
GNUNET_CRYPTO_hash (msg, size, &hash);
|
||||
return TALER_RSA_hash_verify (&hash, sig, publicKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* The blinding key is equal in length to the RSA modulus
|
||||
*/
|
||||
#define TALER_RSA_BLINDING_KEY_LEN TALER_RSA_DATA_ENCODING_LENGTH
|
||||
|
||||
struct TALER_RSA_BlindingKey
|
||||
{
|
||||
/**
|
||||
* The blinding factor
|
||||
*/
|
||||
gcry_mpi_t r;
|
||||
};
|
||||
|
||||
struct TALER_RSA_BlindingKey *
|
||||
TALER_RSA_blinding_key_create ()
|
||||
{
|
||||
struct TALER_RSA_BlindingKey *blind;
|
||||
|
||||
blind = GNUNET_new (struct TALER_RSA_BlindingKey);
|
||||
blind->r = gcry_mpi_new (TALER_RSA_BLINDING_KEY_LEN * 8);
|
||||
gcry_mpi_randomize (blind->r, TALER_RSA_BLINDING_KEY_LEN * 8, GCRY_STRONG_RANDOM);
|
||||
return blind;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TALER_RSA_blinding_key_destroy (struct TALER_RSA_BlindingKey *bkey)
|
||||
{
|
||||
gcry_mpi_release (bkey->r);
|
||||
GNUNET_free (bkey);
|
||||
}
|
||||
|
||||
|
||||
struct TALER_RSA_BlindedSignaturePurpose *
|
||||
TALER_RSA_message_blind (const void *msg, size_t size,
|
||||
struct TALER_RSA_BlindingKey *bkey,
|
||||
struct TALER_RSA_PublicKeyBinaryEncoded *pkey)
|
||||
{
|
||||
struct TALER_RSA_BlindedSignaturePurpose *bsp;
|
||||
struct GNUNET_HashCode hash;
|
||||
gcry_sexp_t psexp;
|
||||
gcry_mpi_t data;
|
||||
gcry_mpi_t skey[2];
|
||||
gcry_mpi_t r_e;
|
||||
gcry_mpi_t data_r_e;
|
||||
size_t rsize;
|
||||
gcry_error_t rc;
|
||||
int ret;
|
||||
|
||||
bsp = NULL;
|
||||
psexp = NULL;
|
||||
data = NULL;
|
||||
skey[0] = skey[1] = NULL;
|
||||
r_e = NULL;
|
||||
data_r_e = NULL;
|
||||
rsize = 0;
|
||||
rc = 0;
|
||||
ret = 0;
|
||||
if (! (psexp = decode_public_key (pkey)))
|
||||
return NULL;
|
||||
ret = key_from_sexp (skey, psexp, "public-key", "ne");
|
||||
if (0 != ret)
|
||||
ret = key_from_sexp (skey, psexp, "rsa", "ne");
|
||||
gcry_sexp_release (psexp);
|
||||
psexp = NULL;
|
||||
GNUNET_assert (0 == ret);
|
||||
GNUNET_CRYPTO_hash (msg, size, &hash);
|
||||
if (0 != (rc=gcry_mpi_scan (&data, GCRYMPI_FMT_USG,
|
||||
(const unsigned char *) msg, size, &rsize)))
|
||||
{
|
||||
LOG_GCRY (GNUNET_ERROR_TYPE_WARNING, "gcry_mpi_scan", rc);
|
||||
goto cleanup;
|
||||
}
|
||||
r_e = gcry_mpi_new (0);
|
||||
gcry_mpi_powm (r_e, bkey->r,
|
||||
skey[1], /* e */
|
||||
skey[0]); /* n */
|
||||
|
||||
data_r_e = gcry_mpi_new (0);
|
||||
gcry_mpi_mulm (data_r_e, data, r_e, skey[0]);
|
||||
|
||||
bsp = GNUNET_new (struct TALER_RSA_BlindedSignaturePurpose);
|
||||
rc = gcry_mpi_print (GCRYMPI_FMT_USG,
|
||||
(unsigned char *) bsp,
|
||||
sizeof (struct TALER_RSA_BlindedSignaturePurpose),
|
||||
&rsize,
|
||||
data_r_e);
|
||||
GNUNET_assert (0 == rc);
|
||||
adjust ((unsigned char *) bsp, rsize,
|
||||
sizeof (struct TALER_RSA_BlindedSignaturePurpose));
|
||||
|
||||
cleanup:
|
||||
if (NULL != psexp) gcry_sexp_release (psexp);
|
||||
mpi_release_non_null (skey[0]);
|
||||
mpi_release_non_null (skey[1]);
|
||||
mpi_release_non_null (data);
|
||||
mpi_release_non_null (r_e);
|
||||
mpi_release_non_null (data_r_e);
|
||||
return bsp;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
TALER_RSA_unblind (struct TALER_RSA_Signature *sig,
|
||||
struct TALER_RSA_BlindingKey *bkey,
|
||||
struct TALER_RSA_PublicKeyBinaryEncoded *pkey)
|
||||
{
|
||||
gcry_sexp_t psexp;
|
||||
gcry_mpi_t skey;
|
||||
gcry_mpi_t sigval;
|
||||
gcry_mpi_t r_inv;
|
||||
gcry_mpi_t ubsig;
|
||||
size_t rsize;
|
||||
gcry_error_t rc;
|
||||
int ret;
|
||||
|
||||
psexp = NULL;
|
||||
skey = NULL;
|
||||
sigval = NULL;
|
||||
r_inv = NULL;
|
||||
ubsig = NULL;
|
||||
rsize = 0;
|
||||
rc = 0;
|
||||
ret = GNUNET_SYSERR;
|
||||
if (! (psexp = decode_public_key (pkey)))
|
||||
return GNUNET_SYSERR;
|
||||
ret = key_from_sexp (&skey, psexp, "public-key", "n");
|
||||
if (0 != ret)
|
||||
ret = key_from_sexp (&skey, psexp, "rsa", "n");
|
||||
gcry_sexp_release (psexp);
|
||||
psexp = NULL;
|
||||
if (0 != (rc = gcry_mpi_scan (&sigval, GCRYMPI_FMT_USG,
|
||||
(const unsigned char *) sig,
|
||||
sizeof (struct TALER_RSA_Signature),
|
||||
&rsize)))
|
||||
{
|
||||
LOG_GCRY (GNUNET_ERROR_TYPE_ERROR, "gcry_mpi_scan", rc);
|
||||
goto cleanup;
|
||||
}
|
||||
r_inv = gcry_mpi_new (0);
|
||||
GNUNET_assert (1 == gcry_mpi_invm (r_inv, bkey->r, skey)); /* n: skey */
|
||||
ubsig = gcry_mpi_new (0);
|
||||
gcry_mpi_mulm (ubsig, sigval, r_inv, skey);
|
||||
rc = gcry_mpi_print (GCRYMPI_FMT_USG,
|
||||
(unsigned char *) sig,
|
||||
sizeof (struct TALER_RSA_Signature),
|
||||
&rsize,
|
||||
ubsig);
|
||||
GNUNET_assert (0 == rc);
|
||||
adjust ((unsigned char *) sig, rsize, sizeof (struct TALER_RSA_Signature));
|
||||
ret = GNUNET_OK;
|
||||
|
||||
cleanup:
|
||||
if (NULL != psexp) gcry_sexp_release (psexp);
|
||||
mpi_release_non_null (skey);
|
||||
mpi_release_non_null (sigval);
|
||||
mpi_release_non_null (r_inv);
|
||||
mpi_release_non_null (ubsig);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Encode a blinding key
|
||||
*
|
||||
* @param bkey the blinding key to encode
|
||||
* @param bkey_enc where to store the encoded binary key
|
||||
* @return #GNUNET_OK upon successful encoding; #GNUNET_SYSERR upon failure
|
||||
*/
|
||||
int
|
||||
TALER_RSA_blinding_key_encode (struct TALER_RSA_BlindingKey *bkey,
|
||||
struct TALER_RSA_BlindingKeyBinaryEncoded *bkey_enc)
|
||||
{
|
||||
GNUNET_abort (); /* FIXME: not implemented */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decode a blinding key from its encoded form
|
||||
*
|
||||
* @param bkey_enc the encoded blinding key
|
||||
* @return the decoded blinding key; NULL upon error
|
||||
*/
|
||||
struct TALER_RSA_BlindingKey *
|
||||
TALER_RSA_blinding_key_decode (struct TALER_RSA_BlindingKeyBinaryEncoded *bkey_enc)
|
||||
{
|
||||
GNUNET_abort (); /* FIXME: not implemented */
|
||||
}
|
||||
|
||||
/* end of util/rsa.c */
|
48
src/util/test_hash_context.c
Normal file
48
src/util/test_hash_context.c
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file util/test_hash_context.c
|
||||
* @brief test case for incremental hashing
|
||||
* @author Florian Dold
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#include "taler_util.h"
|
||||
#include <gcrypt.h>
|
||||
|
||||
#define LEN 1234
|
||||
|
||||
int main()
|
||||
{
|
||||
char data[1234];
|
||||
struct GNUNET_HashCode hc1;
|
||||
struct GNUNET_HashCode hc2;
|
||||
struct TALER_HashContext hctx;
|
||||
|
||||
memset (data, 42, LEN);
|
||||
|
||||
TALER_hash_context_start (&hctx);
|
||||
TALER_hash_context_read (&hctx, data, LEN);
|
||||
TALER_hash_context_finish (&hctx, &hc1);
|
||||
|
||||
GNUNET_CRYPTO_hash (data, LEN, &hc2);
|
||||
|
||||
if (0 == memcmp (&hc1, &hc2, sizeof (struct GNUNET_HashCode)))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
112
src/util/test_rsa.c
Normal file
112
src/util/test_rsa.c
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file util/test_rsa.c
|
||||
* @brief testcase for utility functions for RSA cryptography
|
||||
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||
*/
|
||||
#include "platform.h"
|
||||
#include "taler_rsa.h"
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
|
||||
#define TEST_PURPOSE UINT32_MAX
|
||||
|
||||
|
||||
#define EXITIF(cond) \
|
||||
do { \
|
||||
if (cond) { GNUNET_break (0); goto EXITIF_exit; } \
|
||||
} while (0)
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
#define RND_BLK_SIZE 4096
|
||||
unsigned char rnd_blk[RND_BLK_SIZE];
|
||||
struct TALER_RSA_PrivateKey *priv;
|
||||
struct TALER_RSA_PrivateKeyBinaryEncoded *priv_enc;
|
||||
struct TALER_RSA_PublicKeyBinaryEncoded pubkey;
|
||||
struct TALER_RSA_BlindingKey *bkey;
|
||||
struct TALER_RSA_BlindedSignaturePurpose *bsp;
|
||||
struct TALER_RSA_Signature sig;
|
||||
struct GNUNET_HashCode hash;
|
||||
int ret;
|
||||
|
||||
priv = NULL;
|
||||
bsp = NULL;
|
||||
bkey = NULL;
|
||||
ret = 1;
|
||||
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, rnd_blk,
|
||||
RND_BLK_SIZE);
|
||||
GNUNET_CRYPTO_hash (rnd_blk, RND_BLK_SIZE, &hash);
|
||||
priv = TALER_RSA_key_create ();
|
||||
GNUNET_assert (NULL != priv);
|
||||
EXITIF (GNUNET_OK != TALER_RSA_sign (priv,
|
||||
&hash, sizeof (hash),
|
||||
&sig));
|
||||
TALER_RSA_key_get_public (priv, &pubkey);
|
||||
EXITIF (NULL == (priv_enc = TALER_RSA_encode_key (priv)));
|
||||
TALER_RSA_key_free (priv);
|
||||
priv = NULL;
|
||||
EXITIF (NULL == (priv = TALER_RSA_decode_key ((const char *) priv_enc,
|
||||
ntohs (priv_enc->len))));
|
||||
GNUNET_free (priv_enc);
|
||||
priv_enc = NULL;
|
||||
EXITIF (GNUNET_OK != TALER_RSA_hash_verify (&hash,
|
||||
&sig,
|
||||
&pubkey));
|
||||
EXITIF (GNUNET_OK != TALER_RSA_verify (rnd_blk,
|
||||
RND_BLK_SIZE,
|
||||
&sig,
|
||||
&pubkey));
|
||||
|
||||
/* test blind signing */
|
||||
GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, rnd_blk,
|
||||
RND_BLK_SIZE);
|
||||
GNUNET_CRYPTO_hash (rnd_blk, RND_BLK_SIZE, &hash);
|
||||
(void) memset (&sig, 0, sizeof (struct TALER_RSA_Signature));
|
||||
EXITIF (NULL == (bkey = TALER_RSA_blinding_key_create ()));
|
||||
EXITIF (NULL == (bsp =
|
||||
TALER_RSA_message_blind (&hash, sizeof (hash),
|
||||
bkey, &pubkey)));
|
||||
EXITIF (GNUNET_OK != TALER_RSA_sign (priv,
|
||||
bsp,
|
||||
sizeof (struct TALER_RSA_BlindedSignaturePurpose),
|
||||
&sig));
|
||||
EXITIF (GNUNET_OK != TALER_RSA_unblind (&sig,
|
||||
bkey,
|
||||
&pubkey));
|
||||
EXITIF (GNUNET_OK != TALER_RSA_hash_verify (&hash,
|
||||
&sig,
|
||||
&pubkey));
|
||||
ret = 0; /* all OK */
|
||||
|
||||
EXITIF_exit:
|
||||
if (NULL != priv)
|
||||
{
|
||||
TALER_RSA_key_free (priv);
|
||||
priv = NULL;
|
||||
}
|
||||
if (NULL != priv_enc)
|
||||
{
|
||||
GNUNET_free (priv_enc);
|
||||
priv_enc = NULL;
|
||||
}
|
||||
if (NULL != bkey)
|
||||
TALER_RSA_blinding_key_destroy (bkey);
|
||||
GNUNET_free_non_null (bsp);
|
||||
return ret;
|
||||
}
|
528
src/util/util.c
Normal file
528
src/util/util.c
Normal file
@ -0,0 +1,528 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2014 Christian Grothoff (and other contributing authors)
|
||||
|
||||
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, If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file util.c
|
||||
* @brief Common utility functions
|
||||
* @author Sree Harsha Totakura <sreeharsha@totakura.in>
|
||||
* @author Florian Dold
|
||||
* @author Benedikt Mueller
|
||||
*/
|
||||
|
||||
#include "platform.h"
|
||||
#include "taler_util.h"
|
||||
#include <gnunet/gnunet_common.h>
|
||||
#include <gnunet/gnunet_util_lib.h>
|
||||
#include <gcrypt.h>
|
||||
|
||||
#define CURVE "Ed25519"
|
||||
|
||||
#define AMOUNT_FRAC_BASE 1000000
|
||||
#define AMOUNT_FRAC_LEN 6
|
||||
|
||||
|
||||
|
||||
static void
|
||||
fatal_error_handler (void *cls, int wtf, const char *msg)
|
||||
{
|
||||
LOG_ERROR("Fatal error in Gcrypt: %s\n", msg);
|
||||
abort();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize Gcrypt library.
|
||||
*/
|
||||
void
|
||||
TALER_gcrypt_init()
|
||||
{
|
||||
gcry_set_fatalerror_handler (&fatal_error_handler, NULL);
|
||||
TALER_assert_as(gcry_check_version(NEED_LIBGCRYPT_VERSION),
|
||||
"libgcrypt version mismatch");
|
||||
/* Disable secure memory. */
|
||||
gcry_control (GCRYCTL_DISABLE_SECMEM, 0);
|
||||
gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate a ECC private key.
|
||||
*
|
||||
* @return the s-expression representing the generated ECC private key; NULL
|
||||
* upon error
|
||||
*/
|
||||
gcry_sexp_t
|
||||
TALER_genkey ()
|
||||
{
|
||||
gcry_sexp_t priv_sexp;
|
||||
gcry_sexp_t s_keyparam;
|
||||
int rc;
|
||||
|
||||
if (0 != (rc = gcry_sexp_build (&s_keyparam, NULL,
|
||||
"(genkey(ecc(curve \"" CURVE "\")"
|
||||
"(flags eddsa)))")))
|
||||
{
|
||||
LOG_GCRY_ERROR ("gcry_sexp_build", rc);
|
||||
return NULL;
|
||||
}
|
||||
if (0 != (rc = gcry_pk_genkey (&priv_sexp, s_keyparam)))
|
||||
{
|
||||
LOG_GCRY_ERROR ("gcry_pk_genkey", rc);
|
||||
gcry_sexp_release (s_keyparam);
|
||||
return NULL;
|
||||
}
|
||||
gcry_sexp_release (s_keyparam);
|
||||
if (0 != (rc = gcry_pk_testkey (priv_sexp)))
|
||||
{
|
||||
LOG_GCRY_ERROR("gcry_pk_testkey", rc);
|
||||
gcry_sexp_release (priv_sexp);
|
||||
return NULL;
|
||||
}
|
||||
return priv_sexp;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse money amount description, in the format "A:B.C".
|
||||
*
|
||||
* @param str amount description
|
||||
* @param denom amount to write the result to
|
||||
* @return GNUNET_OK if the string is a valid amount specification,
|
||||
* GNUNET_SYSERR if it is invalid.
|
||||
*/
|
||||
int
|
||||
TALER_string_to_amount (const char *str, struct TALER_Amount *denom)
|
||||
{
|
||||
unsigned int i; // pos in str
|
||||
int n; // number tmp
|
||||
unsigned int c; // currency pos
|
||||
uint32_t b; // base for suffix
|
||||
|
||||
memset (denom, 0, sizeof (struct TALER_Amount));
|
||||
|
||||
i = n = c = 0;
|
||||
|
||||
while (isspace(str[i]))
|
||||
i++;
|
||||
|
||||
if (0 == str[i])
|
||||
{
|
||||
printf("null before currency\n");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
while (str[i] != ':')
|
||||
{
|
||||
if (0 == str[i])
|
||||
{
|
||||
printf("null before colon");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (c > 3)
|
||||
{
|
||||
printf("currency too long\n");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
denom->currency[c] = str[i];
|
||||
c++;
|
||||
i++;
|
||||
}
|
||||
|
||||
// skip colon
|
||||
i++;
|
||||
|
||||
if (0 == str[i])
|
||||
{
|
||||
printf("null before value\n");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
while (str[i] != '.')
|
||||
{
|
||||
if (0 == str[i])
|
||||
{
|
||||
return GNUNET_OK;
|
||||
}
|
||||
n = str[i] - '0';
|
||||
if (n < 0 || n > 9)
|
||||
{
|
||||
printf("invalid character '%c' before comma at %u\n", (char) n, i);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
denom->value = (denom->value * 10) + n;
|
||||
i++;
|
||||
}
|
||||
|
||||
// skip the dot
|
||||
i++;
|
||||
|
||||
if (0 == str[i])
|
||||
{
|
||||
printf("null after dot");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
|
||||
b = 100000;
|
||||
|
||||
while (0 != str[i])
|
||||
{
|
||||
n = str[i] - '0';
|
||||
if (b == 0 || n < 0 || n > 9)
|
||||
{
|
||||
printf("error after comma");
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
denom->fraction += n * b;
|
||||
b /= 10;
|
||||
i++;
|
||||
}
|
||||
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* FIXME
|
||||
*/
|
||||
struct TALER_AmountNBO
|
||||
TALER_amount_hton (struct TALER_Amount d)
|
||||
{
|
||||
struct TALER_AmountNBO dn;
|
||||
dn.value = htonl (d.value);
|
||||
dn.fraction = htonl (d.fraction);
|
||||
memcpy (dn.currency, d.currency, TALER_CURRENCY_LEN);
|
||||
|
||||
return dn;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* FIXME
|
||||
*/
|
||||
struct TALER_Amount
|
||||
TALER_amount_ntoh (struct TALER_AmountNBO dn)
|
||||
{
|
||||
struct TALER_Amount d;
|
||||
d.value = ntohl (dn.value);
|
||||
d.fraction = ntohl (dn.fraction);
|
||||
memcpy (d.currency, dn.currency, sizeof(dn.currency));
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Compare the value/fraction of two amounts. Does not compare the currency,
|
||||
* i.e. comparing amounts with the same value and fraction but different
|
||||
* currency would return 0.
|
||||
*
|
||||
* @param a1 first amount
|
||||
* @param a2 second amount
|
||||
* @return result of the comparison
|
||||
*/
|
||||
int
|
||||
TALER_amount_cmp (struct TALER_Amount a1, struct TALER_Amount a2)
|
||||
{
|
||||
a1 = TALER_amount_normalize (a1);
|
||||
a2 = TALER_amount_normalize (a2);
|
||||
if (a1.value == a2.value)
|
||||
{
|
||||
if (a1.fraction < a2.fraction)
|
||||
return -1;
|
||||
if (a1.fraction > a2.fraction)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
if (a1.value < a2.value)
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform saturating subtraction of amounts.
|
||||
*
|
||||
* @param a1 amount to subtract from
|
||||
* @param a2 amount to subtract
|
||||
* @return (a1-a2) or 0 if a2>=a1
|
||||
*/
|
||||
struct TALER_Amount
|
||||
TALER_amount_subtract (struct TALER_Amount a1, struct TALER_Amount a2)
|
||||
{
|
||||
a1 = TALER_amount_normalize (a1);
|
||||
a2 = TALER_amount_normalize (a2);
|
||||
|
||||
if (a1.value < a2.value)
|
||||
{
|
||||
a1.value = 0;
|
||||
a1.fraction = 0;
|
||||
return a1;
|
||||
}
|
||||
|
||||
if (a1.fraction < a2.fraction)
|
||||
{
|
||||
if (0 == a1.value)
|
||||
{
|
||||
a1.fraction = 0;
|
||||
return a1;
|
||||
}
|
||||
a1.fraction += AMOUNT_FRAC_BASE;
|
||||
a1.value -= 1;
|
||||
}
|
||||
|
||||
a1.fraction -= a2.fraction;
|
||||
a1.value -= a2.value;
|
||||
|
||||
return a1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Perform saturating addition of amounts.
|
||||
*
|
||||
* @param a1 first amount to add
|
||||
* @param a2 second amount to add
|
||||
* @return sum of a1 and a2
|
||||
*/
|
||||
struct TALER_Amount
|
||||
TALER_amount_add (struct TALER_Amount a1, struct TALER_Amount a2)
|
||||
{
|
||||
a1 = TALER_amount_normalize (a1);
|
||||
a2 = TALER_amount_normalize (a2);
|
||||
|
||||
a1.value += a2.value;
|
||||
a1.fraction += a2.fraction;
|
||||
|
||||
if (0 == a1.currency[0])
|
||||
{
|
||||
memcpy (a2.currency, a1.currency, TALER_CURRENCY_LEN);
|
||||
}
|
||||
|
||||
if (0 == a2.currency[0])
|
||||
{
|
||||
memcpy (a1.currency, a2.currency, TALER_CURRENCY_LEN);
|
||||
}
|
||||
|
||||
if (0 != a1.currency[0] && 0 != memcmp (a1.currency, a2.currency, TALER_CURRENCY_LEN))
|
||||
{
|
||||
GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "adding mismatching currencies\n");
|
||||
}
|
||||
|
||||
if (a1.value < a2.value)
|
||||
{
|
||||
a1.value = UINT32_MAX;
|
||||
a2.value = UINT32_MAX;
|
||||
return a1;
|
||||
}
|
||||
|
||||
return TALER_amount_normalize (a1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Normalize the given amount.
|
||||
*
|
||||
* @param amout amount to normalize
|
||||
* @return normalized amount
|
||||
*/
|
||||
struct TALER_Amount
|
||||
TALER_amount_normalize (struct TALER_Amount amount)
|
||||
{
|
||||
while (amount.value != UINT32_MAX && amount.fraction >= AMOUNT_FRAC_BASE)
|
||||
{
|
||||
amount.fraction -= AMOUNT_FRAC_BASE;
|
||||
amount.value += 1;
|
||||
}
|
||||
return amount;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert amount to string.
|
||||
*
|
||||
* @param amount amount to convert to string
|
||||
* @return freshly allocated string representation
|
||||
*/
|
||||
char *
|
||||
TALER_amount_to_string (struct TALER_Amount amount)
|
||||
{
|
||||
char tail[AMOUNT_FRAC_LEN + 1] = { 0 };
|
||||
char curr[TALER_CURRENCY_LEN + 1] = { 0 };
|
||||
char *result = NULL;
|
||||
int len;
|
||||
|
||||
memcpy (curr, amount.currency, TALER_CURRENCY_LEN);
|
||||
|
||||
amount = TALER_amount_normalize (amount);
|
||||
if (0 != amount.fraction)
|
||||
{
|
||||
unsigned int i;
|
||||
uint32_t n = amount.fraction;
|
||||
for (i = 0; (i < AMOUNT_FRAC_LEN) && (n != 0); i++)
|
||||
{
|
||||
tail[i] = '0' + (n / (AMOUNT_FRAC_BASE / 10));
|
||||
n = (n * 10) % (AMOUNT_FRAC_BASE);
|
||||
}
|
||||
tail[i] = 0;
|
||||
len = GNUNET_asprintf (&result, "%s:%lu.%s", curr, (unsigned long) amount.value, tail);
|
||||
}
|
||||
else
|
||||
{
|
||||
len = GNUNET_asprintf (&result, "%s:%lu", curr, (unsigned long) amount.value);
|
||||
}
|
||||
GNUNET_assert (len > 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return the base32crockford encoding of the given buffer.
|
||||
*
|
||||
* The returned string will be freshly allocated, and must be free'd
|
||||
* with GNUNET_free.
|
||||
*
|
||||
* @param buffer with data
|
||||
* @param size size of the buffer
|
||||
* @return freshly allocated, null-terminated string
|
||||
*/
|
||||
char *
|
||||
TALER_data_to_string_alloc (const void *buf, size_t size)
|
||||
{
|
||||
char *str_buf;
|
||||
size_t len = size * 8;
|
||||
char *end;
|
||||
|
||||
if (len % 5 > 0)
|
||||
len += 5 - len % 5;
|
||||
len /= 5;
|
||||
str_buf = GNUNET_malloc (len + 1);
|
||||
end = GNUNET_STRINGS_data_to_string (buf, size, str_buf, len);
|
||||
if (NULL == end)
|
||||
{
|
||||
GNUNET_free (str_buf);
|
||||
return NULL;
|
||||
}
|
||||
*end = '\0';
|
||||
return str_buf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get encoded binary data from a configuration.
|
||||
*
|
||||
* @return GNUNET_OK on success
|
||||
* GNUNET_NO is the value does not exist
|
||||
* GNUNET_SYSERR on encoding error
|
||||
*/
|
||||
int
|
||||
TALER_configuration_get_data (const struct GNUNET_CONFIGURATION_Handle *cfg,
|
||||
const char *section, const char *option,
|
||||
void *buf, size_t buf_size)
|
||||
{
|
||||
char *enc;
|
||||
int res;
|
||||
size_t data_size;
|
||||
if (GNUNET_OK != (res = GNUNET_CONFIGURATION_get_value_string (cfg, section, option, &enc)))
|
||||
return res;
|
||||
data_size = (strlen (enc) * 5) / 8;
|
||||
if (data_size != buf_size)
|
||||
{
|
||||
GNUNET_free (enc);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
if (GNUNET_OK != GNUNET_STRINGS_string_to_data (enc, strlen (enc),
|
||||
buf, buf_size))
|
||||
{
|
||||
GNUNET_free (enc);
|
||||
return GNUNET_SYSERR;
|
||||
}
|
||||
return GNUNET_OK;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
derive_refresh_key (const struct GNUNET_HashCode *secret,
|
||||
struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
|
||||
struct GNUNET_CRYPTO_SymmetricSessionKey *skey)
|
||||
{
|
||||
static const char ctx_key[] = "taler-key-skey";
|
||||
static const char ctx_iv[] = "taler-key-iv";
|
||||
|
||||
GNUNET_assert (GNUNET_YES ==
|
||||
GNUNET_CRYPTO_kdf (skey, sizeof (struct GNUNET_CRYPTO_SymmetricSessionKey),
|
||||
ctx_key, strlen (ctx_key),
|
||||
secret, sizeof (struct GNUNET_HashCode),
|
||||
NULL, 0));
|
||||
GNUNET_assert (GNUNET_YES ==
|
||||
GNUNET_CRYPTO_kdf (iv, sizeof (struct GNUNET_CRYPTO_SymmetricInitializationVector),
|
||||
ctx_iv, strlen (ctx_iv),
|
||||
secret, sizeof (struct GNUNET_HashCode),
|
||||
NULL, 0));
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
TALER_refresh_decrypt (const void *input, size_t input_size, const struct GNUNET_HashCode *secret, void *result)
|
||||
{
|
||||
struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
|
||||
struct GNUNET_CRYPTO_SymmetricSessionKey skey;
|
||||
|
||||
derive_refresh_key (secret, &iv, &skey);
|
||||
|
||||
return GNUNET_CRYPTO_symmetric_decrypt (input, input_size, &skey, &iv, result);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
TALER_refresh_encrypt (const void *input, size_t input_size, const struct GNUNET_HashCode *secret, void *result)
|
||||
{
|
||||
struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
|
||||
struct GNUNET_CRYPTO_SymmetricSessionKey skey;
|
||||
|
||||
derive_refresh_key (secret, &iv, &skey);
|
||||
|
||||
return GNUNET_CRYPTO_symmetric_encrypt (input, input_size, &skey, &iv, result);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TALER_hash_context_start (struct TALER_HashContext *hc)
|
||||
{
|
||||
GNUNET_assert (0 == gcry_md_open (&hc->hd, GCRY_MD_SHA512, 0));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TALER_hash_context_read (struct TALER_HashContext *hc, void *buf, size_t size)
|
||||
{
|
||||
gcry_md_write (hc->hd, buf, size);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TALER_hash_context_finish (struct TALER_HashContext *hc,
|
||||
struct GNUNET_HashCode *r_hash)
|
||||
{
|
||||
void *res = gcry_md_read (hc->hd, 0);
|
||||
GNUNET_assert (NULL != res);
|
||||
if (NULL != r_hash)
|
||||
memcpy (r_hash, res, sizeof (struct GNUNET_HashCode));
|
||||
gcry_md_close (hc->hd);
|
||||
}
|
||||
|
||||
|
||||
/* end of util.c */
|
Loading…
Reference in New Issue
Block a user