-initial import for mint

This commit is contained in:
Christian Grothoff 2015-01-08 18:37:20 +01:00
commit 57d1f08dbc
90 changed files with 19997 additions and 0 deletions

26
.gitignore vendored Normal file
View 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
View File

@ -0,0 +1,3 @@
[submodule "doc/api"]
path = doc/api
url = git@git.taler.net:api

4
AUTHORS Normal file
View File

@ -0,0 +1,4 @@
Sree Harsha Totakura <sreeharsha@totakura.in>
Florian Dold
Christian Grothoff <christian@grothoff.org>
Benedikt Mueller

661
COPYING Normal file
View 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/>.

0
ChangeLog Normal file
View File

370
INSTALL Normal file
View 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
View File

@ -0,0 +1,3 @@
AM_CPPFLAGS = -I$(top_srcdir)/src/include
SUBDIRS = src doc
ACLOCAL_AMFLAGS = -I m4

0
NEWS Normal file
View File

0
README Normal file
View File

2
bootstrap Executable file
View File

@ -0,0 +1,2 @@
#!/bin/sh
autoreconf -if

156
configure.ac Normal file
View 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

View File

@ -0,0 +1 @@
This directory is a template for the mint directory.

View File

@ -0,0 +1,6 @@
[mint]
db = postgres:///taler
port = 4241
master_pub = ...
refresh_security_parameter = 3

View 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
View 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
View File

@ -0,0 +1,5 @@
EXTRA_DIST = \
paper/taler.tex
paper/ref.bib \
paper/Makefile

3474
doc/logos/ai/logotalerv2.ai Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View 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.

View 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.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 368 KiB

15
doc/paper/.latexmkrc Normal file
View 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
View 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
View 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
View File

@ -0,0 +1,9 @@
*.o
*.deps
*.libs
*.lo
*.la
*.log
*.trs
*/__pycache__
test-*

2
src/Makefile.am Normal file
View File

@ -0,0 +1,2 @@
AM_CPPFLAGS = -I$(top_srcdir)/src/include
SUBDIRS = include util mint

7
src/include/Makefile.am Normal file
View 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
View 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
View 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 */

View 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 */

View 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_ */

View 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 cant 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
View 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 */

View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load Diff

283
src/mint/mint_common.c Normal file
View 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

File diff suppressed because it is too large Load Diff

344
src/mint/mint_db.h Normal file
View 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 */

View 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
View 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
View 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

View 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 */

View 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

View 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 */

View 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

View 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 */

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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 */

View 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

View 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
View 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, &params->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, &params->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, &params->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, &params->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, &params->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, &params->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, &params->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, &params->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;
}

View 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
View 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;
}

View 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;
}

View 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;
}

Binary file not shown.

View File

@ -0,0 +1 @@
This directory is a template for the mint directory.

View File

@ -0,0 +1,6 @@
[mint]
db = postgres:///taler
port = 4241
master_pub = 6ZE0HEY2M0FWP61M0470HYBF4K6RRD5DP54372PD2TN9N9VX2VJG
refresh_security_parameter = 3

View 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

View File

@ -0,0 +1 @@
<EFBFBD>W<EFBFBD>B<EFBFBD><EFBFBD>f<EFBFBD> <20><>r<EFBFBD>񷕊<EFBFBD>Ќ<1E><>:<3A><1E>V<07>j

View File

@ -0,0 +1 @@
This directory is a template for the mint directory.

View File

@ -0,0 +1,6 @@
[mint]
db = postgres:///taler
port = 4241
master_pub = 7995WKK71KPKTBBMA5BHNBSZFGNRZPYNXDJMQ8EK86V9598H03TG
refresh_security_parameter = 3

View 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
View 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
View 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
View 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", &currency,
"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
View 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
View 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
View 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 */

View 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
View 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
View 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 */