Big Bang
This commit is contained in:
commit
e8ca5ddb7f
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
*~
|
||||
661
LICENSE
Normal file
661
LICENSE
Normal file
@ -0,0 +1,661 @@
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
147
README.md
Normal file
147
README.md
Normal file
@ -0,0 +1,147 @@
|
||||
# Secure Value Recovery Service (Beta)
|
||||
|
||||
## Building the SGX enclave (optional)
|
||||
|
||||
### Building reproducibly with Docker
|
||||
|
||||
#### Prerequisites:
|
||||
- GNU Make
|
||||
- Docker (able to run debian image)
|
||||
|
||||
`````
|
||||
$ make -C <repository_root>/enclave
|
||||
`````
|
||||
|
||||
The default docker-install target will create a reproducible build environment image using
|
||||
`enclave/docker/Dockerfile`, build the enclave inside a container based on the image, and
|
||||
install the resulting enclave into `service/kbupd/res/enclave/`. The Dockerfile will
|
||||
download a stock dated-snapshot debian Docker image. The Debian project builds their
|
||||
docker images reproducibly, based on the a snapshot of the debian repos on the date of the
|
||||
build from the [Debian Snapshot Project](https://snapshot.debian.org/). Make will then be
|
||||
run inside the newly built Docker Debian image as in the [Building with
|
||||
Debian](#building-with-debian) section below:
|
||||
|
||||
NB: the installed enclave will be signed with the SGX debug flag enabled by an
|
||||
automatically generated signing key. Due to Intel SGX licensing requirements, a debug
|
||||
enclave can currently only be run with SGX debugging enabled, allowing inspection of its
|
||||
encrypted memory, and invalidating its security properties. To use an enclave in
|
||||
production, provide the Intel-whitelisted signing key as
|
||||
`enclave/libkbupd_enclave.hardened.key` before building. Alternatively, the generated
|
||||
`enclave/build/libkbupd_enclave.hardened.signdata` file can be signed and saved as
|
||||
`enclave/build/libkbupd_enclave.sig` with corresponding public key at
|
||||
`enclave/libkbupd_enclave.pub`, and signed using `make sign install`.
|
||||
|
||||
### Building with Debian
|
||||
|
||||
#### Prerequisites:
|
||||
- GNU Make
|
||||
- cmake
|
||||
- ninja-build
|
||||
- gcc
|
||||
- ocaml-native-compilers
|
||||
- ocamlbuild
|
||||
- automake/autoconf/libtool/pkg-config
|
||||
- libssl-dev
|
||||
- libcurl4-openssl-dev
|
||||
- protobuf-compiler
|
||||
- libprotobuf-dev
|
||||
- llvm-dev
|
||||
- libclang-dev
|
||||
- clang
|
||||
- git
|
||||
- devscripts/debhelper/fakeroot
|
||||
- rust 1.37.0 toolchain from rustup
|
||||
- [Intel SGX SDK v2.7.1 SDK](https://github.com/intel/linux-sgx/tree/sgx_2.7.1) build dependencies
|
||||
|
||||
`````
|
||||
$ make -C <repository_root>/enclave debuild install
|
||||
`````
|
||||
|
||||
`debuild` is a debian tool used to build debian packages after it sanitizes the
|
||||
environment and installs build dependences. The primary advantage of using debian
|
||||
packaging tools in this case is to leverage the [Reproducible
|
||||
Builds](https://wiki.debian.org/ReproducibleBuilds) project. While building a debian
|
||||
package, `debuild` will record the names and versions of all detected build dependencies
|
||||
into a *.buildinfo file, for future reproducibility debugging.
|
||||
|
||||
The `debuild` target also builds parts needed from the Intel SGX SDK v2.7.1 after cloning it
|
||||
from github.
|
||||
|
||||
The `install` target copies the enclave to `service/kbupd/res/enclave/`, which should
|
||||
potentially be checked in to be used with the service.
|
||||
|
||||
The `sign` target may also be used as described in [Building reproducibly with
|
||||
Docker](#building-reproducibly-with-docker) to produce a release-mode enclave.
|
||||
|
||||
### Building without Docker or Debian:
|
||||
|
||||
#### Prerequisites:
|
||||
- GNU Make
|
||||
- cmake
|
||||
- ninja-build
|
||||
- gcc
|
||||
- ocaml-native-compilers
|
||||
- ocamlbuild
|
||||
- automake/autoconf/libtool/pkg-config
|
||||
- libssl-dev
|
||||
- libcurl4-openssl-dev
|
||||
- protobuf-compiler
|
||||
- libprotobuf-dev
|
||||
- llvm-dev
|
||||
- libclang-dev
|
||||
- clang
|
||||
- git
|
||||
- rust 1.37.0 toolchain from rustup
|
||||
- [Intel SGX SDK v2.7.1 SDK](https://github.com/intel/linux-sgx/tree/sgx_2.7.1) build dependencies
|
||||
|
||||
`````
|
||||
$ make -C <repository_root>/enclave all install
|
||||
`````
|
||||
|
||||
The `all` target will probably fail to reproduce the same binary as above, but doesn't
|
||||
require Docker or Debian Linux.
|
||||
|
||||
The `sign` target may also be used as described in [Building reproducibly with
|
||||
Docker](#building-reproducibly-with-docker) to produce a release-mode enclave.
|
||||
|
||||
## Building the service
|
||||
|
||||
### Building with Docker
|
||||
|
||||
#### Prerequisites:
|
||||
- GNU Make
|
||||
- Docker (able to run ubuntu image)
|
||||
|
||||
`````
|
||||
$ make -C <repository_root>/service docker
|
||||
`````
|
||||
|
||||
### Building without Docker
|
||||
|
||||
#### Prerequisites:
|
||||
- GNU Make
|
||||
- a C compiler
|
||||
- rust toolchain (i.e. rustc, cargo)
|
||||
- libsgx-enclave-common [from source](https://github.com/intel/linux-sgx/tree/master#install-the-intelr-sgx-psw) or [prebuilt](https://download.01.org/intel-sgx/sgx_repo/ubuntu/pool/main/libs/libsgx-enclave-common/)
|
||||
- libssl-dev (OpenSSL)
|
||||
- libseccomp-dev
|
||||
- pkg-config
|
||||
- protobuf-compiler
|
||||
- [Intel SGX SDK SDK](https://github.com/intel/linux-sgx) headers (common/inc/sgx*.h) installed in a system include directory
|
||||
|
||||
`````
|
||||
$ make -C <repository_root>/service all
|
||||
`````
|
||||
|
||||
## Running the service
|
||||
|
||||
### Runtime requirements:
|
||||
- libsgx-enclave-common >= 2.7.101 [from source](https://github.com/intel/linux-sgx/tree/master#install-the-intelr-sgx-psw) or [prebuilt](https://download.01.org/intel-sgx/sgx_repo/ubuntu/pool/main/libs/libsgx-enclave-common/)
|
||||
- linux-sgx-driver >= 2.6.0 [from source](https://github.com/intel/linux-sgx-driver) or [prebuilt](https://download.01.org/intel-sgx/sgx-linux/2.7.1/distro/ubuntu18.04-server/)
|
||||
- libssl1.1 (OpenSSL)
|
||||
- libseccomp2
|
||||
- libprotobuf10
|
||||
|
||||
`````
|
||||
$ service/build/target/release/kbupd help
|
||||
`````
|
||||
10
enclave/.gitignore
vendored
Normal file
10
enclave/.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
/*.key
|
||||
/*.pub
|
||||
/build
|
||||
/target
|
||||
/debian/.debhelper
|
||||
/debian/debhelper-build-stamp
|
||||
/debian/kbupd-enclave/
|
||||
/debian/kbupd-enclave.substvars
|
||||
/debian/*.deb
|
||||
/debian/files
|
||||
819
enclave/Cargo.lock
generated
Normal file
819
enclave/Cargo.lock
generated
Normal file
@ -0,0 +1,819 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace-sys"
|
||||
version = "0.1.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.10.1"
|
||||
source = "git+https://github.com/marshallpierce/rust-base64.git?rev=07b1d6b713cc2bd7d107185bd0d14bf06cddfb48#07b1d6b713cc2bd7d107185bd0d14bf06cddfb48"
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "2.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/tokio-rs/bytes.git?rev=ebe96021b0eaf52be1fedd0a925f4384275c9cc4#ebe96021b0eaf52be1fedd0a925f4384275c9cc4"
|
||||
|
||||
[[package]]
|
||||
name = "c2-chacha"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.9"
|
||||
source = "git+https://github.com/geogriff-signal/chrono.git?rev=de22e82a1b00b8f015a1d736e497c3177e8e8c9f#de22e82a1b00b8f015a1d736e497c3177e8e8c9f"
|
||||
dependencies = [
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "failure"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "failure_derive"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indoc"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"indoc-impl 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indoc-impl"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unindent 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "intrusive-collections"
|
||||
version = "0.8.1"
|
||||
source = "git+https://github.com/geogriff-signal/intrusive-rs.git?rev=3c14ea97598616a2beaa97cd5fbbb27ba574fe77#3c14ea97598616a2beaa97cd5fbbb27ba574fe77"
|
||||
dependencies = [
|
||||
"memoffset 0.5.1 (git+https://github.com/Gilnaa/memoffset.git?rev=c14a1633760b55999a687bbdf17cb1fa3d1b2f9a)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.4.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "kbupd_enclave"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"base64 0.10.1 (git+https://github.com/marshallpierce/rust-base64.git?rev=07b1d6b713cc2bd7d107185bd0d14bf06cddfb48)",
|
||||
"bytes 0.5.0 (git+https://github.com/tokio-rs/bytes.git?rev=ebe96021b0eaf52be1fedd0a925f4384275c9cc4)",
|
||||
"chrono 0.4.9 (git+https://github.com/geogriff-signal/chrono.git?rev=de22e82a1b00b8f015a1d736e497c3177e8e8c9f)",
|
||||
"hashbrown 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"intrusive-collections 0.8.1 (git+https://github.com/geogriff-signal/intrusive-rs.git?rev=3c14ea97598616a2beaa97cd5fbbb27ba574fe77)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mockers 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mockers_derive 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"no-std-compat 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"prost 0.5.0 (git+https://github.com/geogriff-signal/prost.git?rev=907f7d6e714d0b449d75269d532561c71d3ed250)",
|
||||
"rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.40 (git+https://github.com/geogriff-signal/serde_json.git?rev=d79b0c67f62e168d4872bb8694377ffd97b8949f)",
|
||||
"sgx_ffi 0.1.0",
|
||||
"sgxsd_ffi 0.1.0",
|
||||
"snow 0.6.1 (git+https://github.com/geogriff-signal/snow.git?rev=d8d00a37c8e39b2557d23a26cc4f722595b4f2d9)",
|
||||
"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"test_ffi 0.1.0",
|
||||
"webpki 0.21.0 (git+https://github.com/geogriff-signal/webpki.git?rev=32ab63c46edfbfe9c1fe68008ba8e247eb387ca3)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.62"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "memoffset"
|
||||
version = "0.5.1"
|
||||
source = "git+https://github.com/Gilnaa/memoffset.git?rev=c14a1633760b55999a687bbdf17cb1fa3d1b2f9a#c14a1633760b55999a687bbdf17cb1fa3d1b2f9a"
|
||||
dependencies = [
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mockers"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"select-rustc 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mockers_derive"
|
||||
version = "0.21.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"indoc 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-quote 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "no-std-compat"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "4.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.30"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-quote"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-quote-impl 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-quote-impl"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/geogriff-signal/prost.git?rev=907f7d6e714d0b449d75269d532561c71d3ed250#907f7d6e714d0b449d75269d532561c71d3ed250"
|
||||
dependencies = [
|
||||
"bytes 0.5.0 (git+https://github.com/tokio-rs/bytes.git?rev=ebe96021b0eaf52be1fedd0a925f4384275c9cc4)",
|
||||
"prost-derive 0.5.0 (git+https://github.com/geogriff-signal/prost.git?rev=907f7d6e714d0b449d75269d532561c71d3ed250)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prost-derive"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/geogriff-signal/prost.git?rev=907f7d6e714d0b449d75269d532561c71d3ed250#907f7d6e714d0b449d75269d532561c71d3ed250"
|
||||
dependencies = [
|
||||
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.16.9"
|
||||
source = "git+https://github.com/geogriff-signal/ring.git?rev=d0b3a4dcf1f24a2700280f9f7541cb5079398ec6#d0b3a4dcf1f24a2700280f9f7541cb5079398ec6"
|
||||
dependencies = [
|
||||
"cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"untrusted 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "select-rustc"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.40"
|
||||
source = "git+https://github.com/geogriff-signal/serde_json.git?rev=d79b0c67f62e168d4872bb8694377ffd97b8949f#d79b0c67f62e168d4872bb8694377ffd97b8949f"
|
||||
dependencies = [
|
||||
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sgx_ffi"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mockers 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mockers_derive 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"test_ffi 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sgxsd_ffi"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mockers 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mockers_derive 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sgx_ffi 0.1.0",
|
||||
"test_ffi 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "snow"
|
||||
version = "0.6.1"
|
||||
source = "git+https://github.com/geogriff-signal/snow.git?rev=d8d00a37c8e39b2557d23a26cc4f722595b4f2d9#d8d00a37c8e39b2557d23a26cc4f722595b4f2d9"
|
||||
dependencies = [
|
||||
"arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"subtle 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sourcefile"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "subtle"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "test_ffi"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mockers 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mockers_derive 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unindent"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-macro 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-shared 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-macro-support 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-backend 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-shared 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-webidl"
|
||||
version = "0.2.50"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-backend 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"js-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"wasm-bindgen-webidl 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki"
|
||||
version = "0.21.0"
|
||||
source = "git+https://github.com/geogriff-signal/webpki.git?rev=32ab63c46edfbfe9c1fe68008ba8e247eb387ca3#32ab63c46edfbfe9c1fe68008ba8e247eb387ca3"
|
||||
dependencies = [
|
||||
"ring 0.16.9 (git+https://github.com/geogriff-signal/ring.git?rev=d0b3a4dcf1f24a2700280f9f7541cb5079398ec6)",
|
||||
"untrusted 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "weedle"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
|
||||
"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875"
|
||||
"checksum backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "690a62be8920ccf773ee00ef0968649b0e724cda8bd5b12286302b4ae955fdf5"
|
||||
"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b"
|
||||
"checksum base64 0.10.1 (git+https://github.com/marshallpierce/rust-base64.git?rev=07b1d6b713cc2bd7d107185bd0d14bf06cddfb48)" = "<none>"
|
||||
"checksum bumpalo 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ad807f2fc2bf185eeb98ff3a901bd46dc5ad58163d0fa4577ba0d25674d71708"
|
||||
"checksum bytes 0.5.0 (git+https://github.com/tokio-rs/bytes.git?rev=ebe96021b0eaf52be1fedd0a925f4384275c9cc4)" = "<none>"
|
||||
"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101"
|
||||
"checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be"
|
||||
"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
|
||||
"checksum chrono 0.4.9 (git+https://github.com/geogriff-signal/chrono.git?rev=de22e82a1b00b8f015a1d736e497c3177e8e8c9f)" = "<none>"
|
||||
"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
|
||||
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
|
||||
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
|
||||
"checksum hashbrown 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bcea5b597dd98e6d1f1ec171744cc5dee1a30d1c23c5b98e3cf9d4fbdf8a526"
|
||||
"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
|
||||
"checksum indoc 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3f9553c1e16c114b8b77ebeb329e5f2876eed62a8d51178c8bc6bff0d65f98f8"
|
||||
"checksum indoc-impl 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b714fc08d0961716390977cdff1536234415ac37b509e34e5a983def8340fb75"
|
||||
"checksum intrusive-collections 0.8.1 (git+https://github.com/geogriff-signal/intrusive-rs.git?rev=3c14ea97598616a2beaa97cd5fbbb27ba574fe77)" = "<none>"
|
||||
"checksum itertools 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)" = "c4a9b56eb56058f43dc66e58f40a214b2ccbc9f3df51861b63d51dec7b65bc3f"
|
||||
"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
|
||||
"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
|
||||
"checksum js-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)" = "1efc4f2a556c58e79c5500912e221dd826bec64ff4aabd8ce71ccef6da02d7d4"
|
||||
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
|
||||
"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba"
|
||||
"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
|
||||
"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
|
||||
"checksum memoffset 0.5.1 (git+https://github.com/Gilnaa/memoffset.git?rev=c14a1633760b55999a687bbdf17cb1fa3d1b2f9a)" = "<none>"
|
||||
"checksum mockers 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8bf36d14570661eebd299640fff1fae157c6d7da34bcbf4e4eba1c3b47b46ec9"
|
||||
"checksum mockers_derive 0.21.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a53c3de46bf8e9cbe2b80e5086bbc8659bdf508c3719d50c2f366c9368d5726c"
|
||||
"checksum no-std-compat 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df270209a7f04d62459240d890ecb792714d5db12c92937823574a09930276b4"
|
||||
"checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6"
|
||||
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
|
||||
"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
|
||||
"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b"
|
||||
"checksum proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e688f31d92ffd7c1ddc57a1b4e6d773c0f2a14ee437a4b0a4f5a69c80eb221c8"
|
||||
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
|
||||
"checksum proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afdc77cc74ec70ed262262942ebb7dac3d479e9e5cfa2da1841c0806f6cdabcc"
|
||||
"checksum proc-quote 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fa612543f23fda013e1e6ce30b5285a9d313c6e582e57b4ceca74eb5b85685b5"
|
||||
"checksum proc-quote-impl 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f785f0f8cd00b7945efc3f3bdf8205eb06af5aacec598d83e67f41dc8d101fda"
|
||||
"checksum prost 0.5.0 (git+https://github.com/geogriff-signal/prost.git?rev=907f7d6e714d0b449d75269d532561c71d3ed250)" = "<none>"
|
||||
"checksum prost-derive 0.5.0 (git+https://github.com/geogriff-signal/prost.git?rev=907f7d6e714d0b449d75269d532561c71d3ed250)" = "<none>"
|
||||
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
|
||||
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
|
||||
"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412"
|
||||
"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
|
||||
"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||
"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
"checksum ring 0.16.9 (git+https://github.com/geogriff-signal/ring.git?rev=d0b3a4dcf1f24a2700280f9f7541cb5079398ec6)" = "<none>"
|
||||
"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
|
||||
"checksum select-rustc 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fdb2e15b35a72de428af0da95ba4c990a336602576906f537923c5aa4d695835"
|
||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd"
|
||||
"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e"
|
||||
"checksum serde_json 1.0.40 (git+https://github.com/geogriff-signal/serde_json.git?rev=d79b0c67f62e168d4872bb8694377ffd97b8949f)" = "<none>"
|
||||
"checksum snow 0.6.1 (git+https://github.com/geogriff-signal/snow.git?rev=d8d00a37c8e39b2557d23a26cc4f722595b4f2d9)" = "<none>"
|
||||
"checksum sourcefile 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf77cb82ba8453b42b6ae1d692e4cdc92f9a47beaf89a847c8be83f4e328ad3"
|
||||
"checksum spin 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
"checksum subtle 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "01f40907d9ffc762709e4ff3eb4a6f6b41b650375a3f09ac92b641942b7fb082"
|
||||
"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5"
|
||||
"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
|
||||
"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
|
||||
"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||
"checksum unindent 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c7d0d32a92c9ed197278e09140c32dec854ad5826f0e0e18c1d2a1690f15c8d5"
|
||||
"checksum untrusted 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60369ef7a31de49bcb3f6ca728d4ba7300d9a1658f94c727d4cab8c8d9f4aece"
|
||||
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
|
||||
"checksum wasm-bindgen 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "dcddca308b16cd93c2b67b126c688e5467e4ef2e28200dc7dfe4ae284f2faefc"
|
||||
"checksum wasm-bindgen-backend 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "f805d9328b5fc7e5c6399960fd1889271b9b58ae17bdb2417472156cc9fafdd0"
|
||||
"checksum wasm-bindgen-macro 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "3ff88201a482abfc63921621f6cb18eb1efd74f136b05e5841e7f8ca434539e9"
|
||||
"checksum wasm-bindgen-macro-support 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "6a433d89ecdb9f77d46fcf00c8cf9f3467b7de9954d8710c175f61e2e245bb0e"
|
||||
"checksum wasm-bindgen-shared 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "d41fc1bc3570cdf8d108c15e014045fd45a95bb5eb36605f96a90461fc34027d"
|
||||
"checksum wasm-bindgen-webidl 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)" = "be53d289bf2fa7645a089cfd5c7a34bf4fe94221f58cf86ee42a7b4bc854ff14"
|
||||
"checksum web-sys 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)" = "6435c477200ad486089a7a72c2bd6c9bdf9740bd7fff868806076218076d8c51"
|
||||
"checksum webpki 0.21.0 (git+https://github.com/geogriff-signal/webpki.git?rev=32ab63c46edfbfe9c1fe68008ba8e247eb387ca3)" = "<none>"
|
||||
"checksum weedle 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3bb43f70885151e629e2a19ce9e50bd730fd436cfd4b666894c9ce4de9141164"
|
||||
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
10
enclave/Cargo.toml
Normal file
10
enclave/Cargo.toml
Normal file
@ -0,0 +1,10 @@
|
||||
[workspace]
|
||||
members = ["kbupd_enclave", "sgx_ffi", "sgxsd_ffi", "test_ffi"]
|
||||
|
||||
[patch.crates-io]
|
||||
ring = { rev = "d0b3a4dcf1f24a2700280f9f7541cb5079398ec6", git = "https://github.com/geogriff-signal/ring.git" }
|
||||
bytes = { rev = "ebe96021b0eaf52be1fedd0a925f4384275c9cc4", git = "https://github.com/tokio-rs/bytes.git" }
|
||||
memoffset = { rev = "c14a1633760b55999a687bbdf17cb1fa3d1b2f9a", git = "https://github.com/Gilnaa/memoffset.git" }
|
||||
|
||||
[profile.release]
|
||||
lto = "fat"
|
||||
297
enclave/Makefile
Normal file
297
enclave/Makefile
Normal file
@ -0,0 +1,297 @@
|
||||
sgxsd_srcdir = sgxsd_enclave
|
||||
includedir = include
|
||||
patchdir = patches
|
||||
builddir = build
|
||||
targetdir = $(builddir)/target
|
||||
resourcedir = ../service/kbupd/res
|
||||
|
||||
RUSTC ?= rustc
|
||||
CARGO ?= cargo
|
||||
RUSTUP ?= rustup
|
||||
BINDGEN ?= $(builddir)/bin/bindgen-0.51.1
|
||||
DOCKER ?= docker
|
||||
INSTALL ?= install
|
||||
|
||||
RUSTUP_TOOLCHAIN_UNSTABLE ?= nightly
|
||||
|
||||
FEATURES ?=
|
||||
|
||||
INSTALL_PROGRAM = $(INSTALL) -m 755 $(INSTALL_PROGRAM_FLAGS)
|
||||
INSTALL_DATA = $(INSTALL) -m 644
|
||||
|
||||
DESTDIR ?=
|
||||
|
||||
CFLAGS = \
|
||||
-m64 -O2 -ggdb -march=skylake -pipe -fPIC \
|
||||
-D_FORTIFY_SOURCE=2 -std=c11 -D_DEFAULT_SOURCE \
|
||||
-fstack-protector-strong -fcf-protection \
|
||||
-Wall -Werror=all -Wextra -Wno-unused-parameter -Wno-missing-field-initializers \
|
||||
-I$(includedir) -I$(includedir)/bearssl -I$(SGX_INCLUDEDIR)
|
||||
|
||||
LDFLAGS =
|
||||
|
||||
ENCLAVE_RUSTFLAGS = -C opt-level=2 -C debuginfo=1 -C codegen-units=1 -C panic=abort -Z allow_features=alloc_error_handler,thread_local -C llvm-args=-max-jump-table-size=1 -C llvm-args=-disable-tail-duplicate
|
||||
|
||||
BINDGENFLAGS =
|
||||
CARGOBUILDFLAGS =
|
||||
export CARGO_TARGET_DIR = $(CURDIR)/$(targetdir)
|
||||
export CARGO_HOME = $(CURDIR)/$(builddir)/cargo
|
||||
|
||||
TEST_CFLAGS += $(CFLAGS) \
|
||||
-DUNIT_TESTING -fsanitize=address -static-libasan -fsanitize=undefined -static-libubsan
|
||||
|
||||
##
|
||||
## sgxsd
|
||||
##
|
||||
|
||||
TEST_SGXSD_TARGET := $(builddir)/sgxsd-enclave-test
|
||||
|
||||
BEARSSL_SOURCES := \
|
||||
$(sgxsd_srcdir)/bearssl/gcm.c $(sgxsd_srcdir)/bearssl/ghash_pclmul.c \
|
||||
$(sgxsd_srcdir)/bearssl/sha2small.c $(sgxsd_srcdir)/bearssl/dec32be.c $(sgxsd_srcdir)/bearssl/enc32be.c \
|
||||
$(sgxsd_srcdir)/bearssl/aes_x86ni_ctr.c $(sgxsd_srcdir)/bearssl/aes_x86ni.c
|
||||
BEARSSL_OBJECTS := $(addprefix $(builddir)/,$(BEARSSL_SOURCES:.c=.o))
|
||||
|
||||
SGXSD_SOURCES := $(sgxsd_srcdir)/sgxsd-enclave.c $(sgxsd_srcdir)/curve25519-donna-c64.c $(BEARSSL_SOURCES) \
|
||||
$(sgxsd_srcdir)/sgx-tcrypto-stub.c
|
||||
SGXSD_OBJECTS := $(addprefix $(builddir)/,$(SGXSD_SOURCES:.c=.o))
|
||||
|
||||
TEST_SGXSD_SOURCES := $(sgxsd_srcdir)/sgxsd-enclave.c $(sgxsd_srcdir)/curve25519-donna-c64.c $(sgxsd_srcdir)/sgxsd-enclave-test.c $(sgxsd_srcdir)/cmockery.c
|
||||
TEST_SGXSD_OBJECTS := $(addprefix $(builddir)/test/,$(TEST_SGXSD_SOURCES:.c=.o))
|
||||
|
||||
TEST_LDFLAGS += $(TEST_CFLAGS)
|
||||
|
||||
##
|
||||
## kbupd
|
||||
##
|
||||
|
||||
KBUPD_ENCLAVE_NAME := libkbupd_enclave.hardened
|
||||
KBUPD_ENCLAVE_TARGET := $(builddir)/libkbupd_enclave.unstripped.so
|
||||
KBUPD_ENCLAVE_RUST_STATICLIB := $(targetdir)/release/libkbupd_enclave.a
|
||||
|
||||
##
|
||||
## targets
|
||||
##
|
||||
|
||||
.PHONY: default docker-install all unstripped hardened unsigned llvm-bolt doc check test test-asan benchmark clippy bindgen protobuf debug sign install edger8r distclean clean docker
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o
|
||||
|
||||
default: docker-install
|
||||
|
||||
include sgx_enclave.mk
|
||||
|
||||
docker-install: docker install
|
||||
|
||||
all: $(KBUPD_ENCLAVE_TARGET) $(builddir)/$(KBUPD_ENCLAVE_NAME).unstripped.so $(builddir)/$(KBUPD_ENCLAVE_NAME).unsigned.so $(builddir)/$(KBUPD_ENCLAVE_NAME).debug.so $(builddir)/$(KBUPD_ENCLAVE_NAME).signdata $(builddir)/$(KBUPD_ENCLAVE_NAME).mrenclave
|
||||
|
||||
unstripped: $(KBUPD_ENCLAVE_TARGET)
|
||||
|
||||
hardened: $(builddir)/$(KBUPD_ENCLAVE_NAME).unstripped.so
|
||||
|
||||
unsigned: $(builddir)/$(KBUPD_ENCLAVE_NAME).unsigned.so
|
||||
|
||||
llvm-bolt: $(LLVM_BOLT)
|
||||
|
||||
doc:
|
||||
env -u CFLAGS RUSTC_BOOTSTRAP=1 RUSTFLAGS="$(ENCLAVE_RUSTFLAGS)" \
|
||||
$(CARGO) doc --package=kbupd_enclave --release --document-private-items --lib
|
||||
|
||||
check:
|
||||
$(CARGO) check --package=kbupd_enclave --lib --tests
|
||||
|
||||
test: $(TEST_SGXSD_TARGET)
|
||||
ASAN_OPTIONS="detect_leaks=0:$(ASAN_OPTIONS)" ./$(TEST_SGXSD_TARGET)
|
||||
env -u CFLAGS \
|
||||
RUST_BACKTRACE=full \
|
||||
RUST_TEST_THREADS=1 \
|
||||
$(CARGO) test --all --exclude=kbupd_enclave -- --test-threads=1
|
||||
env -u CFLAGS \
|
||||
RUST_BACKTRACE=full \
|
||||
RUST_TEST_THREADS=1 \
|
||||
$(CARGO) test --manifest-path=kbupd_enclave/Cargo.toml --lib --bins --features test -- --test-threads=1
|
||||
|
||||
test-asan: $(TEST_SGXSD_TARGET)
|
||||
./$(TEST_SGXSD_TARGET)
|
||||
env -u CFLAGS \
|
||||
RUST_BACKTRACE=full \
|
||||
RUSTFLAGS="-Z sanitizer=address" RUST_TEST_THREADS=1 \
|
||||
ASAN_OPTIONS="detect_odr_violation=1:detect_stack_use_after_return=true:check_initialization_order=true:strict_init_order=true:halt_on_error=false:$(ASAN_OPTIONS)" \
|
||||
LSAN_OPTIONS="suppressions=$(CURDIR)/kbupd_enclave/lsan-ignore-test.txt:$(LSAN_OPTIONS)" \
|
||||
$(RUSTUP) run $(RUSTUP_TOOLCHAIN_UNSTABLE) \
|
||||
$(CARGO) test --all --exclude=kbupd_enclave -- --test-threads=1
|
||||
env -u CFLAGS \
|
||||
RUST_BACKTRACE=full \
|
||||
RUSTFLAGS="-Z sanitizer=address" RUST_TEST_THREADS=1 \
|
||||
ASAN_OPTIONS="detect_odr_violation=1:detect_stack_use_after_return=true:check_initialization_order=true:strict_init_order=true:halt_on_error=false:$(ASAN_OPTIONS)" \
|
||||
LSAN_OPTIONS="suppressions=$(CURDIR)/kbupd_enclave/lsan-ignore-test.txt:$(LSAN_OPTIONS)" \
|
||||
$(RUSTUP) run $(RUSTUP_TOOLCHAIN_UNSTABLE) \
|
||||
$(CARGO) test --manifest-path=kbupd_enclave/Cargo.toml --lib --bins --tests --features=test -- --test-threads=1
|
||||
|
||||
clippy:
|
||||
$(CARGO) clippy --all --exclude=kbupd_enclave
|
||||
$(CARGO) clippy --manifest-path=kbupd_enclave/Cargo.toml --features=test
|
||||
|
||||
benchmark:
|
||||
$(CARGO) bench --all
|
||||
|
||||
bindgen: $(BINDGEN) | $(SGX_INCLUDEDIR)
|
||||
$(BINDGEN) --no-include-path-detection -o sgx_ffi/src/bindgen_wrapper.rs \
|
||||
--rust-target 1.33 --use-core --ctypes-prefix libc --with-derive-default --with-derive-eq --no-prepend-enum-name \
|
||||
sgx_ffi/src/bindgen_wrapper.h -- \
|
||||
$(filter-out -fvisibility=hidden,$(filter-out -std=%,$(CFLAGS) $(ENCLAVE_CFLAGS)))
|
||||
$(BINDGEN) --no-include-path-detection -o sgxsd_ffi/src/bindgen_wrapper.rs \
|
||||
--rust-target 1.33 --use-core --ctypes-prefix libc --with-derive-default --with-derive-eq --no-prepend-enum-name \
|
||||
sgxsd_ffi/src/bindgen_wrapper.h -- \
|
||||
$(filter-out -fvisibility=hidden,$(filter-out -std=%,$(CFLAGS) $(ENCLAVE_CFLAGS)))
|
||||
$(BINDGEN) --no-include-path-detection -o kbupd_enclave/src/ffi/bindgen_wrapper.rs \
|
||||
--rust-target 1.33 --use-core --ctypes-prefix libc --with-derive-default --with-derive-eq --no-prepend-enum-name \
|
||||
kbupd_enclave/src/ffi/bindgen_wrapper.h -- \
|
||||
$(filter-out -fvisibility=hidden,$(filter-out -std=%,$(CFLAGS) $(ENCLAVE_CFLAGS)))
|
||||
|
||||
$(builddir)/bin/bindgen-%:
|
||||
$(CARGO) install --force --version $* --bin bindgen bindgen
|
||||
mkdir -p $(builddir)/bin
|
||||
cp $(builddir)/cargo/bin/bindgen $@
|
||||
|
||||
protobuf: | $(targetdir)/debug/prostc
|
||||
mkdir -p kbupd_enclave/src/protobufs
|
||||
OUT_DIR=kbupd_enclave/src/protobufs $(targetdir)/debug/prostc kbupd_enclave/src/protobufs.proto kbupd_enclave/src/ $(includedir)/
|
||||
mv kbupd_enclave/src/protobufs/protobufs.rs kbupd_enclave/src/protobufs/mod.rs
|
||||
cd kbupd_enclave/src/protobufs; for file in protobufs.*.rs; do newfile=$${file#protobufs.}; mv $$file $$newfile; echo "pub mod $${newfile%.rs};" >> mod.rs; done
|
||||
|
||||
|
||||
debug: $(builddir)/$(KBUPD_ENCLAVE_NAME).unsigned.so $(builddir)/$(KBUPD_ENCLAVE_NAME).debug.so
|
||||
|
||||
sign: $(builddir)/$(KBUPD_ENCLAVE_NAME).signed.so $(builddir)/$(KBUPD_ENCLAVE_NAME).test.signed.so
|
||||
|
||||
install:
|
||||
$(INSTALL_DATA) $(builddir)/$(KBUPD_ENCLAVE_NAME).debug.so \
|
||||
$(resourcedir)/enclave/$$(cat $(builddir)/$(KBUPD_ENCLAVE_NAME).mrenclave).so
|
||||
if [ -e $(builddir)/$(KBUPD_ENCLAVE_NAME).signed.so ]; then \
|
||||
cp $(builddir)/$(KBUPD_ENCLAVE_NAME).signed.so \
|
||||
$(resourcedir)/enclave/$$(cat $(builddir)/$(KBUPD_ENCLAVE_NAME).mrenclave).so; \
|
||||
fi
|
||||
|
||||
edger8r: $(includedir)/kbupd_enclave.edl | $(SGX_EDGER8R)
|
||||
$(SGX_EDGER8R) --untrusted --untrusted-dir $(includedir) \
|
||||
--trusted --trusted-dir $(includedir) \
|
||||
--search-path $(SGX_INCLUDEDIR) \
|
||||
--search-path $(includedir) \
|
||||
$(includedir)/kbupd_enclave.edl
|
||||
|
||||
distclean: clean
|
||||
|
||||
clean:
|
||||
rm -f $(builddir)/$(KBUPD_ENCLAVE_NAME).debug.signdata \
|
||||
$(builddir)/$(KBUPD_ENCLAVE_NAME).debug.key \
|
||||
$(builddir)/$(KBUPD_ENCLAVE_NAME).debug.pub \
|
||||
$(builddir)/$(KBUPD_ENCLAVE_NAME).debug.sig \
|
||||
$(builddir)/$(KBUPD_ENCLAVE_NAME).test.sig \
|
||||
$(builddir)/$(KBUPD_ENCLAVE_NAME).test.signdata \
|
||||
$(builddir)/$(KBUPD_ENCLAVE_NAME).sig \
|
||||
$(builddir)/$(KBUPD_ENCLAVE_NAME).signdata \
|
||||
$(builddir)/$(KBUPD_ENCLAVE_NAME).mrenclave \
|
||||
$(builddir)/*.o \
|
||||
$(builddir)/*.a \
|
||||
$(builddir)/*.so \
|
||||
$(SGXSD_OBJECTS) $(TEST_SGXSD_TARGET) $(TEST_SGXSD_OBJECTS) \
|
||||
debian/debhelper-build-stamp \
|
||||
debian/kbupd-enclave.substvars \
|
||||
debian/files \
|
||||
debian/*.deb
|
||||
-rm -r $(targetdir)/release/ \
|
||||
$(targetdir)/debug/ \
|
||||
$(builddir)/bolt/build \
|
||||
$(builddir)/cargo/bin \
|
||||
$(SGX_SDK_SOURCE_DIR) \
|
||||
debian/.debhelper/ \
|
||||
debian/kbupd-enclave/
|
||||
-$(CARGO) clean --release
|
||||
|
||||
## rust
|
||||
|
||||
.PHONY: FORCE
|
||||
FORCE:
|
||||
|
||||
$(targetdir)/debug/prostc: FORCE
|
||||
env -u CFLAGS $(CARGO) build --manifest-path=prostc/Cargo.toml --bin=prostc
|
||||
$(targetdir)/release/lib%.a: FORCE
|
||||
env CFLAGS="" RUSTC_BOOTSTRAP=1 RUSTFLAGS="$(ENCLAVE_RUSTFLAGS)" \
|
||||
$(CARGO) build -vv --release --package=$* --lib $(if $(FEATURES),--features $(FEATURES))
|
||||
|
||||
## sgxsd
|
||||
|
||||
$(BEARSSL_OBJECTS): $(wildcard $(includedir)/bearssl/%.h)
|
||||
$(SGXSD_OBJECTS): $(builddir)/%.o: %.c $(includedir)/sgxsd.h $(includedir)/sgxsd-enclave.h | $(SGX_INCLUDEDIR)
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) -o $@ $(CFLAGS) $(ENCLAVE_CFLAGS) -c $<
|
||||
|
||||
$(TEST_SGXSD_TARGET): $(TEST_SGXSD_OBJECTS)
|
||||
$(CC) -o $@ $(TEST_SGXSD_OBJECTS) $(TEST_LDFLAGS)
|
||||
$(TEST_SGXSD_OBJECTS): $(builddir)/test/%.o: %.c $(includedir)/sgxsd.h $(includedir)/sgxsd-enclave.h $(includedir)/cmockery.h | $(SGX_INCLUDEDIR)
|
||||
@mkdir -p $(dir $@)
|
||||
$(CC) -o $@ $(CFLAGS) $(TEST_CFLAGS) -c $<
|
||||
|
||||
## kbupd
|
||||
|
||||
$(includedir)/kbupd_enclave_t.h $(includedir)/kbupd_enclave_u.h: $(includedir)/sgxsd.edl
|
||||
|
||||
$(builddir)/kbupd_enclave_t.o: $(includedir)/kbupd_enclave_t.c
|
||||
$(CC) -o $@ $(CFLAGS) $(ENCLAVE_CFLAGS) -c $<
|
||||
|
||||
$(builddir)/kbupd_enclave_u.o: $(includedir)/kbupd_enclave_u.c
|
||||
$(CC) -o $@ $(CFLAGS) -c $<
|
||||
|
||||
$(builddir)/libkbupd_enclave_u.a: $(builddir)/kbupd_enclave_u.o
|
||||
$(AR) r $@ $<
|
||||
|
||||
$(KBUPD_ENCLAVE_TARGET): $(SGXSD_OBJECTS) $(KBUPD_ENCLAVE_RUST_STATICLIB)
|
||||
$(KBUPD_ENCLAVE_TARGET): LDFLAGS := -L$(dir $(KBUPD_ENCLAVE_RUST_STATICLIB))
|
||||
$(KBUPD_ENCLAVE_TARGET): LDLIBS := -lkbupd_enclave
|
||||
|
||||
## Reproducible enclave build via debian package
|
||||
|
||||
MAKETARGET ?= bindgen debuild sign
|
||||
|
||||
docker: DOCKER_EXTRA=$(shell [ -L build ] && P=$$(readlink build) && echo -v $$P/:$$P )
|
||||
docker:
|
||||
$(DOCKER) build --build-arg UID=$$(id -u) --build-arg GID=$$(id -g) \
|
||||
-t kbupd-enclave-builder ./docker
|
||||
$(DOCKER) run -it --rm --user $$(id -u):$$(id -g) --cap-add SYS_PTRACE \
|
||||
-v `pwd`/:/home/signal/src $(DOCKER_EXTRA) kbupd-enclave-builder \
|
||||
sh -c "cd src; make $(MAKETARGET)"
|
||||
|
||||
.PHONY: debuild
|
||||
debuild:
|
||||
env -u LANG LC_ALL=C debuild --preserve-envvar=PATH --no-lintian --build=binary -uc -us -j1
|
||||
mv ../*.buildinfo debian/buildinfo
|
||||
mv ../*.deb debian/
|
||||
|
||||
.PHONY: debuild-kbupd-enclave-build
|
||||
debuild-kbupd-enclave-build: all
|
||||
|
||||
.PHONY: debuild-kbupd-enclave-install
|
||||
debuild-kbupd-enclave-install: $(builddir)/$(KBUPD_ENCLAVE_NAME).unsigned.so
|
||||
mkdir -p $(DESTDIR)/usr/lib/kbupd/enclave/
|
||||
$(INSTALL_DATA) $(builddir)/$(KBUPD_ENCLAVE_NAME).unsigned.so $(DESTDIR)/usr/lib/kbupd/enclave/
|
||||
|
||||
.PHONY: debuild-kbupd-enclave-test
|
||||
debuild-kbupd-enclave-test:
|
||||
echo "not running tests in debuild" 1>&2
|
||||
|
||||
.PHONY: tar
|
||||
tar:
|
||||
tar -cjf $(builddir)/$(KBUPD_ENCLAVE_NAME).build.tar.bz2 \
|
||||
$(LLVM_BOLT) \
|
||||
--anchored --exclude-vcs \
|
||||
--exclude='$(builddir)/bolt' \
|
||||
--exclude='$(builddir)/cargo/registry/cache' \
|
||||
--exclude='$(builddir)/cargo/registry/index' \
|
||||
--exclude='$(builddir)/cargo/git/db' \
|
||||
--exclude='*.git' \
|
||||
--no-wildcards-match-slash \
|
||||
--exclude='$(builddir)/*.tar.bz2' \
|
||||
--verbose --totals \
|
||||
'$(builddir)/'
|
||||
189
enclave/bin/gc_functions
Executable file
189
enclave/bin/gc_functions
Executable file
@ -0,0 +1,189 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import sys, re, subprocess
|
||||
from collections import namedtuple
|
||||
|
||||
Function = namedtuple('Function', 'length length_instructions offset refs')
|
||||
|
||||
start_func = re.compile(r'^([0-9a-f]+) <(.+)>:$')
|
||||
|
||||
instruction = re.compile(r'^\s*[0-9a-f]+:\s+((?:[0-9a-f]{2} )+)\s*([0-9a-z()]+)?(?:\w+(.+))?\w*$')
|
||||
instruction_ref = re.compile(r'^[^<]*(?:<([^>+]+)(?:[+]([^>]+))?>)?$')
|
||||
|
||||
entry_point = re.compile(r'^\s*Entry point address:\s+0x([0-9a-f]+)$')
|
||||
|
||||
data_line = re.compile(r'^\s*0x[0-9a-f]+ ([0-9a-f]+) ([0-9a-f]+) ([0-9a-f]+) ([0-9a-f]+) .+$')
|
||||
|
||||
global_text = re.compile(r'^[0-9a-f]+ T (.+)$')
|
||||
|
||||
def parse(disasm):
|
||||
funcs = {}
|
||||
|
||||
cur_func = None
|
||||
cur_offset = 0
|
||||
cur_len = 0
|
||||
cur_len_instructions = 0
|
||||
cur_refs = None
|
||||
for line in disasm:
|
||||
line = line.rstrip('\n')
|
||||
|
||||
if len(line) == 0:
|
||||
continue
|
||||
|
||||
if line.startswith('Disassembly of section '):
|
||||
continue
|
||||
|
||||
m = start_func.match(line)
|
||||
if m:
|
||||
if cur_func:
|
||||
funcs[cur_func] = Function(length = cur_len,
|
||||
length_instructions = cur_len_instructions,
|
||||
offset = cur_offset,
|
||||
refs = cur_refs)
|
||||
cur_func = m.group(2)
|
||||
cur_offset = m.group(1)
|
||||
cur_len = 0
|
||||
cur_len_instructions = 0
|
||||
cur_refs = set()
|
||||
|
||||
continue
|
||||
|
||||
if not cur_func:
|
||||
continue
|
||||
|
||||
m = instruction.match(line)
|
||||
if m:
|
||||
instruction_bytes = m.group(1)
|
||||
instruction_opcode = m.group(2)
|
||||
instruction_operands = m.group(3)
|
||||
if not instruction_opcode:
|
||||
#Padding. As a hack decrement isns count, since it isn't really one.
|
||||
cur_len_instructions -= 1
|
||||
if instruction_operands:
|
||||
ref_match = instruction_ref.match(instruction_operands)
|
||||
if ref_match:
|
||||
ref = ref_match.group(1)
|
||||
if ref:
|
||||
cur_refs.add(ref.split('+')[0])
|
||||
cur_len_instructions += 1
|
||||
cur_len += instruction_bytes.count(' ')
|
||||
else:
|
||||
print("Couldn't parse '%s' " % line)
|
||||
assert(False)
|
||||
|
||||
if cur_func:
|
||||
funcs[cur_func] = Function(length = cur_len,
|
||||
length_instructions = cur_len_instructions,
|
||||
offset = cur_offset,
|
||||
refs = cur_refs)
|
||||
|
||||
for key in tuple(funcs.keys()):
|
||||
if key.startswith('.'):
|
||||
del(funcs[key])
|
||||
|
||||
return funcs
|
||||
|
||||
def get_roots(binary, funcs):
|
||||
roots = set()
|
||||
candidates = []
|
||||
|
||||
inv_funcs = {v.offset: k for k, v in funcs.items()}
|
||||
|
||||
#Get the entry point, and scan various data sections for possible function pointers.
|
||||
sections = [ '.data.rel.ro', '.rodata', '.data' ]
|
||||
section_args = [ v for pair in zip(['-x'] * 3, sections) for v in pair ]
|
||||
readelf = subprocess.run(['readelf', '-W', '-h', *section_args, binary],
|
||||
stdout=subprocess.PIPE, universal_newlines=True)
|
||||
for l in readelf.stdout.split('\n'):
|
||||
m = entry_point.match(l)
|
||||
if m:
|
||||
roots.add(inv_funcs[m.group(1).rjust(16, '0')])
|
||||
|
||||
m = data_line.match(l)
|
||||
if m:
|
||||
#XXX This misses the trailing line if it has less than 16 bytes.
|
||||
for i in 1, 3:
|
||||
hi = m.group(i+1)
|
||||
lo = m.group(i)
|
||||
candidates.append("%s%s%s%s%s%s%s%s" % (hi[6:8], hi[4:6], hi[2:4], hi[0:2],
|
||||
lo[6:8], lo[4:6], lo[2:4], lo[0:2]))
|
||||
|
||||
for c in candidates:
|
||||
f = inv_funcs.get(c)
|
||||
if f:
|
||||
roots.add(f)
|
||||
|
||||
#Get exported .text segment symbols.
|
||||
nm = subprocess.run(['nm', '-g', binary], stdout=subprocess.PIPE, universal_newlines=True)
|
||||
for l in nm.stdout.split('\n'):
|
||||
m = global_text.match(l)
|
||||
if m:
|
||||
roots.add(m.group(1))
|
||||
|
||||
return roots
|
||||
|
||||
def mark(root, funcs, markset):
|
||||
# if root == 'GFp_bn_sqr8x_internal':
|
||||
# import inspect
|
||||
# raise Exception([f.frame.f_locals['root'] for f in inspect.stack() if f.function == 'mark'])
|
||||
markset.add(root)
|
||||
for ref in funcs[root].refs:
|
||||
if ref == root:
|
||||
continue
|
||||
if ref in markset:
|
||||
continue
|
||||
if ref in funcs:
|
||||
mark(ref, funcs, markset)
|
||||
|
||||
def clobber(binary, clobbers, funcs):
|
||||
with open(binary, 'r+b') as binfile:
|
||||
for clobber in clobbers:
|
||||
func = funcs[clobber]
|
||||
offset = int(func.offset, 16)
|
||||
clobber_bytes = b'\xcc' * (func.length - 1)
|
||||
clobber_bytes += b'\xc3'
|
||||
binfile.seek(offset)
|
||||
binfile.write(clobber_bytes)
|
||||
|
||||
def main():
|
||||
assert(sys.argv[1].endswith('.so'))
|
||||
|
||||
disasm = subprocess.Popen(['objdump', '-d', sys.argv[1]],
|
||||
stdout=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
funcs = parse(disasm.stdout)
|
||||
|
||||
roots = get_roots(sys.argv[1], funcs)
|
||||
print("Found %s roots" % len(roots))
|
||||
|
||||
marks = set()
|
||||
for root in roots:
|
||||
mark(root, funcs, marks)
|
||||
|
||||
deads = set(funcs) - marks
|
||||
|
||||
to_clobber = set()
|
||||
byte_cnt = 0
|
||||
for dead in deads:
|
||||
#if dead.startswith("_Z"):
|
||||
# continue #Skip Rust code for now.
|
||||
byte_cnt += funcs[dead].length
|
||||
print("Dead: %s - %s isns %s:%s" % (dead, funcs[dead].length_instructions,
|
||||
funcs[dead].offset, funcs[dead].length))
|
||||
to_clobber.add(dead)
|
||||
|
||||
print('Dead/Total functions: %s/%s (%.2f%%)' % (len(to_clobber), len(funcs),
|
||||
len(to_clobber)/len(funcs)*100.0))
|
||||
|
||||
byte_total = 0
|
||||
for f in funcs.values():
|
||||
byte_total += f.length
|
||||
print('Dead bytes/Total bytes: %s/%s (%.2f%%)' % (byte_cnt, byte_total,
|
||||
byte_cnt/byte_total*100.0))
|
||||
|
||||
if len(sys.argv) >= 3 and sys.argv[2] == '--clobber':
|
||||
clobber(sys.argv[1], to_clobber, funcs)
|
||||
print('Clobbered %s functions' % len(to_clobber))
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
17
enclave/bin/sgx-gdb
Executable file
17
enclave/bin/sgx-gdb
Executable file
@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
|
||||
for dir in build/linux-sgx-* $(dir $0)/build/linux-sgx-*; do
|
||||
if [ -d "$dir/build/linux" ]; then
|
||||
SGX_SDK_SOURCE_DIR="$dir"
|
||||
fi
|
||||
done
|
||||
if [ -z "$SGX_SDK_SOURCE_DIR" ]; then
|
||||
echo "please set \$SGX_SDK_SOURCE_DIR"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
GDB_SGX_PLUGIN_PATH=${SGX_SDK_SOURCE_DIR}/build/linux/gdb-sgx-plugin
|
||||
|
||||
export PYTHONPATH=$GDB_SGX_PLUGIN_PATH
|
||||
export SGX_DBG_OPTIN=1
|
||||
LD_PRELOAD="${SGX_SDK_SOURCE_DIR}/build/linux/libsgx_ptrace.so" gdb -iex "directory ${GDB_SGX_PLUGIN_PATH}" -iex "source ${GDB_SGX_PLUGIN_PATH}/gdb_sgx_plugin.py" -iex "set environment LD_PRELOAD" -iex "add-auto-load-safe-path /usr/lib" "$@"
|
||||
0
enclave/bolt_skip_funcs.txt
Normal file
0
enclave/bolt_skip_funcs.txt
Normal file
29
enclave/ci/azure-pipelines/enclave.yml
Normal file
29
enclave/ci/azure-pipelines/enclave.yml
Normal file
@ -0,0 +1,29 @@
|
||||
#
|
||||
# Azure Pipeline to reproducibly build the backup enclave. Triggers on tags matching enclave-*.
|
||||
#
|
||||
|
||||
pr: none
|
||||
|
||||
trigger:
|
||||
branches:
|
||||
include:
|
||||
- refs/tags/enclave-*
|
||||
|
||||
resources:
|
||||
containers:
|
||||
- container: kbupd-enclave-builder
|
||||
image: signalbackupci:kbupd-enclave-builder
|
||||
endpoint: signalbackupci-container-registry
|
||||
options: --user 0:0
|
||||
|
||||
stages:
|
||||
- stage: docker_build_kbupd_enclave_builder
|
||||
displayName: docker build kbupd-enclave-builder
|
||||
jobs:
|
||||
- template: jobs/docker_build_kbupd_enclave_builder.yml
|
||||
|
||||
- stage: make_all
|
||||
displayName: make all
|
||||
dependsOn: docker_build_kbupd_enclave_builder
|
||||
jobs:
|
||||
- template: jobs/make_all.yml
|
||||
@ -0,0 +1,38 @@
|
||||
#
|
||||
# Azure Pipelines job to build the kbupd-enclave-builder docker image used to build the enclave
|
||||
#
|
||||
|
||||
jobs:
|
||||
- job: docker_build_kbupd_enclave_builder
|
||||
displayName: docker build kbupd-enclave-builder
|
||||
pool:
|
||||
vmImage: ubuntu-18.04
|
||||
steps:
|
||||
- task: Docker@2
|
||||
displayName: docker login
|
||||
inputs:
|
||||
command: login
|
||||
containerRegistry: signalbackupci-container-registry
|
||||
|
||||
- script: docker pull signalbackupci.azurecr.io/signalbackupci:kbupd-enclave-builder || true
|
||||
displayName: docker pull
|
||||
|
||||
- task: Docker@2
|
||||
displayName: docker build
|
||||
inputs:
|
||||
command: build
|
||||
dockerfile: enclave/docker/Dockerfile
|
||||
arguments: --build-arg UID=1001 --build-arg GID=1001 --cache-from signalbackupci.azurecr.io/signalbackupci:kbupd-enclave-builder
|
||||
repository: signalbackupci
|
||||
tags: |
|
||||
kbupd-enclave-builder
|
||||
kbupd-enclave-builder-$(Build.SourceVersion)
|
||||
|
||||
- task: Docker@2
|
||||
displayName: docker push
|
||||
inputs:
|
||||
command: push
|
||||
repository: signalbackupci
|
||||
tags: |
|
||||
kbupd-enclave-builder
|
||||
kbupd-enclave-builder-$(Build.SourceVersion)
|
||||
52
enclave/ci/azure-pipelines/jobs/make_all.yml
Normal file
52
enclave/ci/azure-pipelines/jobs/make_all.yml
Normal file
@ -0,0 +1,52 @@
|
||||
#
|
||||
# Azure Pipelines job to build the enclave from within in the kbupd-enclave-builder docker image.
|
||||
#
|
||||
|
||||
jobs:
|
||||
- job: make_all
|
||||
displayName: make all
|
||||
pool:
|
||||
vmImage: ubuntu-18.04
|
||||
container: kbupd-enclave-builder
|
||||
timeoutInMinutes: 120
|
||||
steps:
|
||||
- script: |
|
||||
cp -a enclave /home/signal/src && \
|
||||
mkdir enclave/build/ && \
|
||||
ln -s `pwd`/enclave/build /home/signal/src/build
|
||||
displayName: set up build directory
|
||||
|
||||
- task: CacheBeta@1
|
||||
displayName: cached enclave/build/bin/
|
||||
inputs:
|
||||
path: enclave/build/bin/
|
||||
key: enclave/docker/Dockerfile | enclave/docker/apt.conf | enclave/docker/sources.list | enclave/sgx_enclave.mk | "$(Build.SourceBranch)"
|
||||
restoreKeys:
|
||||
enclave/docker/Dockerfile | enclave/docker/apt.conf | enclave/docker/sources.list | enclave/sgx_enclave.mk | "refs/heads/$(System.PullRequest.TargetBranch)"
|
||||
|
||||
enclave/docker/Dockerfile | enclave/docker/apt.conf | enclave/docker/sources.list | enclave/sgx_enclave.mk
|
||||
|
||||
- script: make -C /home/signal/src/ bindgen
|
||||
displayName: make bindgen
|
||||
|
||||
- script: make -C /home/signal/src/ debuild
|
||||
displayName: make debuild
|
||||
|
||||
- publish: enclave/build/libkbupd_enclave.unstripped.so
|
||||
artifact: libkbupd_enclave.unstripped.so
|
||||
- publish: enclave/build/libkbupd_enclave.hardened.unstripped.so
|
||||
artifact: libkbupd_enclave.hardened.unstripped.so
|
||||
- publish: enclave/build/libkbupd_enclave.hardened.unsigned.so
|
||||
artifact: libkbupd_enclave.hardened.unsigned.so
|
||||
- publish: enclave/build/libkbupd_enclave.hardened.signdata
|
||||
artifact: libkbupd_enclave.hardened.signdata
|
||||
- publish: enclave/build/libkbupd_enclave.hardened.mrenclave
|
||||
artifact: libkbupd_enclave.hardened.mrenclave
|
||||
- publish: enclave/build/bin/llvm-bolt
|
||||
artifact: llvm-bolt
|
||||
|
||||
- script: make -C /home/signal/src/ tar
|
||||
displayName: make tar
|
||||
|
||||
- publish: enclave/build/libkbupd_enclave.hardened.build.tar.bz2
|
||||
artifact: libkbupd_enclave.hardened.build.tar.bz2
|
||||
13
enclave/ci/azure-pipelines/jobs/make_test.yml
Normal file
13
enclave/ci/azure-pipelines/jobs/make_test.yml
Normal file
@ -0,0 +1,13 @@
|
||||
#
|
||||
# Azure Pipelines job to run all enclave tests from within in the kbupd-enclave-builder docker image.
|
||||
#
|
||||
|
||||
jobs:
|
||||
- job: make_test
|
||||
displayName: make test
|
||||
pool:
|
||||
vmImage: ubuntu-18.04
|
||||
container: kbupd-enclave-builder
|
||||
steps:
|
||||
- script: make -C enclave/ test
|
||||
displayName: make test
|
||||
44
enclave/ci/azure-pipelines/master.yml
Normal file
44
enclave/ci/azure-pipelines/master.yml
Normal file
@ -0,0 +1,44 @@
|
||||
#
|
||||
# Azure Pipeline to build & test the backup enclave. Triggers on commits and PRs to master in enclave/.
|
||||
#
|
||||
|
||||
pr:
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
paths:
|
||||
include:
|
||||
- enclave/
|
||||
|
||||
trigger:
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
paths:
|
||||
include:
|
||||
- enclave/
|
||||
|
||||
resources:
|
||||
containers:
|
||||
- container: kbupd-enclave-builder
|
||||
image: signalbackupci:kbupd-enclave-builder
|
||||
endpoint: signalbackupci-container-registry
|
||||
options: --user 0:0
|
||||
|
||||
stages:
|
||||
- stage: docker_build_kbupd_enclave_builder
|
||||
displayName: docker build kbupd-enclave-builder
|
||||
jobs:
|
||||
- template: jobs/docker_build_kbupd_enclave_builder.yml
|
||||
|
||||
- stage: make_test
|
||||
displayName: make test
|
||||
dependsOn: docker_build_kbupd_enclave_builder
|
||||
jobs:
|
||||
- template: jobs/make_test.yml
|
||||
|
||||
- stage: make_all
|
||||
displayName: make all
|
||||
dependsOn: docker_build_kbupd_enclave_builder
|
||||
jobs:
|
||||
- template: jobs/make_all.yml
|
||||
209
enclave/debian/buildinfo
Normal file
209
enclave/debian/buildinfo
Normal file
@ -0,0 +1,209 @@
|
||||
Format: 1.0
|
||||
Source: kbupd-enclave
|
||||
Binary: kbupd-enclave
|
||||
Architecture: amd64
|
||||
Version: 1.0
|
||||
Checksums-Md5:
|
||||
59ef215ccc0d2628535a2a92d45ec15d 583248 kbupd-enclave_1.0_amd64.deb
|
||||
Checksums-Sha1:
|
||||
e7ece57ea7b04ced54dbe4edb1d1d0d3eae1760d 583248 kbupd-enclave_1.0_amd64.deb
|
||||
Checksums-Sha256:
|
||||
27fa91826311e79327241f0f067a819ebdaf1f8713ed33e19fa78362a457d218 583248 kbupd-enclave_1.0_amd64.deb
|
||||
Build-Origin: Debian
|
||||
Build-Architecture: amd64
|
||||
Build-Date: Mon, 18 Nov 2019 00:18:32 +0000
|
||||
Installed-Build-Depends:
|
||||
autoconf (= 2.69-11),
|
||||
automake (= 1:1.16.1-4),
|
||||
autopoint (= 0.19.8.1-9),
|
||||
autotools-dev (= 20180224.1),
|
||||
base-files (= 10.3+deb10u1),
|
||||
base-passwd (= 3.5.46),
|
||||
bash (= 5.0-4),
|
||||
binutils (= 2.31.1-16),
|
||||
binutils-common (= 2.31.1-16),
|
||||
binutils-x86-64-linux-gnu (= 2.31.1-16),
|
||||
bsdmainutils (= 11.1.2+b1),
|
||||
bsdutils (= 1:2.33.1-0.1),
|
||||
build-essential (= 12.6),
|
||||
bzip2 (= 1.0.6-9.2~deb10u1),
|
||||
clang-7 (= 1:7.0.1-8),
|
||||
coreutils (= 8.30-3),
|
||||
cpp (= 4:8.3.0-1),
|
||||
cpp-8 (= 8.3.0-6),
|
||||
curl (= 7.64.0-4),
|
||||
dash (= 0.5.10.2-5),
|
||||
debconf (= 1.5.71),
|
||||
debhelper (= 12.1.1),
|
||||
debianutils (= 4.8.6.1),
|
||||
dh-autoreconf (= 19),
|
||||
dh-strip-nondeterminism (= 1.1.2-1),
|
||||
diffutils (= 1:3.7-3),
|
||||
dpkg (= 1.19.7),
|
||||
dpkg-dev (= 1.19.7),
|
||||
dwz (= 0.12-3),
|
||||
fdisk (= 2.33.1-0.1),
|
||||
file (= 1:5.35-4),
|
||||
findutils (= 4.6.0+git+20190209-2),
|
||||
g++ (= 4:8.3.0-1),
|
||||
g++-8 (= 8.3.0-6),
|
||||
gcc (= 4:8.3.0-1),
|
||||
gcc-8 (= 8.3.0-6),
|
||||
gcc-8-base (= 8.3.0-6),
|
||||
gettext (= 0.19.8.1-9),
|
||||
gettext-base (= 0.19.8.1-9),
|
||||
git (= 1:2.20.1-2),
|
||||
git-man (= 1:2.20.1-2),
|
||||
grep (= 3.3-1),
|
||||
groff-base (= 1.22.4-3),
|
||||
gzip (= 1.9-3),
|
||||
hostname (= 3.21),
|
||||
init-system-helpers (= 1.56+nmu1),
|
||||
intltool-debian (= 0.35.0+20060710.5),
|
||||
lib32gcc1 (= 1:8.3.0-6),
|
||||
lib32stdc++6 (= 8.3.0-6),
|
||||
libacl1 (= 2.2.53-4),
|
||||
libarchive-zip-perl (= 1.64-1),
|
||||
libasan5 (= 8.3.0-6),
|
||||
libatomic1 (= 8.3.0-6),
|
||||
libattr1 (= 1:2.4.48-4),
|
||||
libaudit-common (= 1:2.8.4-3),
|
||||
libaudit1 (= 1:2.8.4-3),
|
||||
libbinutils (= 2.31.1-16),
|
||||
libblkid1 (= 2.33.1-0.1),
|
||||
libbsd0 (= 0.9.1-2),
|
||||
libbz2-1.0 (= 1.0.6-9.2~deb10u1),
|
||||
libc-bin (= 2.28-10),
|
||||
libc-dev-bin (= 2.28-10),
|
||||
libc6 (= 2.28-10),
|
||||
libc6-dev (= 2.28-10),
|
||||
libc6-i386 (= 2.28-10),
|
||||
libcap-ng0 (= 0.7.9-2),
|
||||
libcc1-0 (= 8.3.0-6),
|
||||
libclang-common-7-dev (= 1:7.0.1-8),
|
||||
libclang1-7 (= 1:7.0.1-8),
|
||||
libcom-err2 (= 1.44.5-1+deb10u2),
|
||||
libcroco3 (= 0.6.12-3),
|
||||
libcurl3-gnutls (= 7.64.0-4),
|
||||
libcurl4 (= 7.64.0-4),
|
||||
libcurl4-openssl-dev (= 7.64.0-4),
|
||||
libdb5.3 (= 5.3.28+dfsg1-0.5),
|
||||
libdebconfclient0 (= 0.249),
|
||||
libdpkg-perl (= 1.19.7),
|
||||
libedit2 (= 3.1-20181209-1),
|
||||
libelf1 (= 0.176-1.1),
|
||||
liberror-perl (= 0.17027-2),
|
||||
libexpat1 (= 2.2.6-2+deb10u1),
|
||||
libfdisk1 (= 2.33.1-0.1),
|
||||
libffi6 (= 3.2.1-9),
|
||||
libfile-stripnondeterminism-perl (= 1.1.2-1),
|
||||
libgc1c2 (= 1:7.6.4-0.4),
|
||||
libgcc-8-dev (= 8.3.0-6),
|
||||
libgcc1 (= 1:8.3.0-6),
|
||||
libgcrypt20 (= 1.8.4-5),
|
||||
libgdbm-compat4 (= 1.18.1-4),
|
||||
libgdbm6 (= 1.18.1-4),
|
||||
libglib2.0-0 (= 2.58.3-2+deb10u1),
|
||||
libgmp10 (= 2:6.1.2+dfsg-4),
|
||||
libgnutls30 (= 3.6.7-4),
|
||||
libgomp1 (= 8.3.0-6),
|
||||
libgpg-error0 (= 1.35-1),
|
||||
libgssapi-krb5-2 (= 1.17-3),
|
||||
libhogweed4 (= 3.4.1-1),
|
||||
libicu63 (= 63.1-6),
|
||||
libidn2-0 (= 2.0.5-1),
|
||||
libisl19 (= 0.20-2),
|
||||
libitm1 (= 8.3.0-6),
|
||||
libk5crypto3 (= 1.17-3),
|
||||
libkeyutils1 (= 1.6-6),
|
||||
libkrb5-3 (= 1.17-3),
|
||||
libkrb5support0 (= 1.17-3),
|
||||
libldap-2.4-2 (= 2.4.47+dfsg-3+deb10u1),
|
||||
libldap-common (= 2.4.47+dfsg-3+deb10u1),
|
||||
libllvm7 (= 1:7.0.1-8),
|
||||
liblsan0 (= 8.3.0-6),
|
||||
liblz4-1 (= 1.8.3-1),
|
||||
liblzma5 (= 5.2.4-1),
|
||||
libmagic-mgc (= 1:5.35-4),
|
||||
libmagic1 (= 1:5.35-4),
|
||||
libmount1 (= 2.33.1-0.1),
|
||||
libmpc3 (= 1.1.0-1),
|
||||
libmpfr6 (= 4.0.2-1),
|
||||
libmpx2 (= 8.3.0-6),
|
||||
libncurses-dev (= 6.1+20181013-2+deb10u1),
|
||||
libncurses5-dev (= 6.1+20181013-2+deb10u1),
|
||||
libncurses6 (= 6.1+20181013-2+deb10u1),
|
||||
libncursesw6 (= 6.1+20181013-2+deb10u1),
|
||||
libnettle6 (= 3.4.1-1),
|
||||
libnghttp2-14 (= 1.36.0-2+deb10u1),
|
||||
libobjc-8-dev (= 8.3.0-6),
|
||||
libobjc4 (= 8.3.0-6),
|
||||
libp11-kit0 (= 0.23.15-2),
|
||||
libpam-modules (= 1.3.1-5),
|
||||
libpam-modules-bin (= 1.3.1-5),
|
||||
libpam-runtime (= 1.3.1-5),
|
||||
libpam0g (= 1.3.1-5),
|
||||
libpcre2-8-0 (= 10.32-5),
|
||||
libpcre3 (= 2:8.39-12),
|
||||
libperl5.28 (= 5.28.1-6),
|
||||
libpipeline1 (= 1.5.1-2),
|
||||
libprotobuf-dev (= 3.6.1.3-2),
|
||||
libprotobuf-lite17 (= 3.6.1.3-2),
|
||||
libprotobuf17 (= 3.6.1.3-2),
|
||||
libpsl5 (= 0.20.2-2),
|
||||
libquadmath0 (= 8.3.0-6),
|
||||
librtmp1 (= 2.4+20151223.gitfa8646d.1-2),
|
||||
libsasl2-2 (= 2.1.27+dfsg-1),
|
||||
libsasl2-modules-db (= 2.1.27+dfsg-1),
|
||||
libseccomp2 (= 2.3.3-4),
|
||||
libselinux1 (= 2.8-1+b1),
|
||||
libsigsegv2 (= 2.12-2),
|
||||
libsmartcols1 (= 2.33.1-0.1),
|
||||
libssh2-1 (= 1.8.0-2.1),
|
||||
libssl-dev (= 1.1.1d-0+deb10u2),
|
||||
libssl1.1 (= 1.1.1d-0+deb10u2),
|
||||
libstdc++-8-dev (= 8.3.0-6),
|
||||
libstdc++6 (= 8.3.0-6),
|
||||
libsystemd0 (= 241-7~deb10u1),
|
||||
libtasn1-6 (= 4.13-3),
|
||||
libtinfo6 (= 6.1+20181013-2+deb10u1),
|
||||
libtool (= 2.4.6-9),
|
||||
libtsan0 (= 8.3.0-6),
|
||||
libubsan1 (= 8.3.0-6),
|
||||
libuchardet0 (= 0.0.6-3),
|
||||
libudev1 (= 241-7~deb10u1),
|
||||
libunistring2 (= 0.9.10-1),
|
||||
libuuid1 (= 2.33.1-0.1),
|
||||
libxml2 (= 2.9.4+dfsg1-7+b3),
|
||||
linux-libc-dev (= 4.19.67-2+deb10u1),
|
||||
login (= 1:4.5-1.1),
|
||||
m4 (= 1.4.18-2),
|
||||
make (= 4.2.1-1.2),
|
||||
man-db (= 2.8.5-2),
|
||||
mawk (= 1.3.3-17+b3),
|
||||
ncurses-base (= 6.1+20181013-2+deb10u1),
|
||||
ncurses-bin (= 6.1+20181013-2+deb10u1),
|
||||
ocaml-base-nox (= 4.05.0-11),
|
||||
ocaml-compiler-libs (= 4.05.0-11),
|
||||
ocaml-interp (= 4.05.0-11),
|
||||
ocaml-nox (= 4.05.0-11),
|
||||
patch (= 2.7.6-3+deb10u1),
|
||||
perl (= 5.28.1-6),
|
||||
perl-base (= 5.28.1-6),
|
||||
perl-modules-5.28 (= 5.28.1-6),
|
||||
pkg-config (= 0.29-6),
|
||||
po-debconf (= 1.0.21),
|
||||
sed (= 4.7-1),
|
||||
sensible-utils (= 0.0.12),
|
||||
sysvinit-utils (= 2.93-8),
|
||||
tar (= 1.30+dfsg-6),
|
||||
util-linux (= 2.33.1-0.1),
|
||||
wget (= 1.20.1-1.1),
|
||||
xz-utils (= 5.2.4-1),
|
||||
zlib1g (= 1:1.2.11.dfsg-1),
|
||||
zlib1g-dev (= 1:1.2.11.dfsg-1)
|
||||
Environment:
|
||||
DEB_BUILD_OPTIONS="parallel=1"
|
||||
LC_ALL="C"
|
||||
MAKEFLAGS=" -j1"
|
||||
SOURCE_DATE_EPOCH="1543475532"
|
||||
5
enclave/debian/changelog
Normal file
5
enclave/debian/changelog
Normal file
@ -0,0 +1,5 @@
|
||||
kbupd-enclave (1.0) unstable; urgency=medium
|
||||
|
||||
*
|
||||
|
||||
-- Jeffrey Griffin <jeff@signal.org> Wed, 28 Nov 2018 23:12:12 -0800
|
||||
1
enclave/debian/compat
Normal file
1
enclave/debian/compat
Normal file
@ -0,0 +1 @@
|
||||
10
|
||||
25
enclave/debian/control
Normal file
25
enclave/debian/control
Normal file
@ -0,0 +1,25 @@
|
||||
Source: kbupd-enclave
|
||||
Section: database
|
||||
Priority: optional
|
||||
Maintainer: Jeffrey Griffin <jeff@signal.org>
|
||||
Build-Depends:
|
||||
debhelper (>= 10),
|
||||
automake,
|
||||
autoconf,
|
||||
libtool,
|
||||
curl,
|
||||
wget,
|
||||
git,
|
||||
ocaml-native-compilers,
|
||||
pkg-config,
|
||||
libssl-dev,
|
||||
libprotobuf-dev,
|
||||
libcurl4-openssl-dev,
|
||||
Standards-Version: 4.0.0
|
||||
|
||||
Package: kbupd-enclave
|
||||
Architecture: amd64
|
||||
Depends:
|
||||
${misc:Depends},
|
||||
Description: Key Backup Service Enclave library
|
||||
Signal's Key Backup Service Enclave library
|
||||
668
enclave/debian/copyright
Normal file
668
enclave/debian/copyright
Normal file
@ -0,0 +1,668 @@
|
||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: kbupd-enclave
|
||||
Source: <https://github.com/signalapp/KeyBackupService>
|
||||
|
||||
Files: *
|
||||
Copyright: Copyright (C) 2018 Open Whisper Systems
|
||||
License: AGPL-3+
|
||||
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/>.
|
||||
16
enclave/debian/rules
Executable file
16
enclave/debian/rules
Executable file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/make -f
|
||||
export DH_VERBOSE = 1
|
||||
export DEB_BUILD_MAINT_OPTIONS=qa=-all sanitize=-all hardening=-all reproducible=-all parallel=1
|
||||
unexport LANG
|
||||
export LC_ALL=C
|
||||
%:
|
||||
dh $@ --no-parallel
|
||||
|
||||
override_dh_auto_build:
|
||||
dh_auto_build -- debuild-kbupd-enclave-build
|
||||
|
||||
override_dh_auto_install:
|
||||
make DESTDIR=debian/kbupd-enclave debuild-kbupd-enclave-install
|
||||
|
||||
override_dh_auto_test:
|
||||
dh_auto_build -- debuild-kbupd-enclave-test
|
||||
1
enclave/debian/source/format
Normal file
1
enclave/debian/source/format
Normal file
@ -0,0 +1 @@
|
||||
3.0 (native)
|
||||
2
enclave/debian/source/lintian-overrides
Normal file
2
enclave/debian/source/lintian-overrides
Normal file
@ -0,0 +1,2 @@
|
||||
shared-lib-without-dependency-information usr/lib/kbupd/enclave/*.so
|
||||
shlib-with-executable-stack usr/lib/kbupd/enclave/*.so
|
||||
42
enclave/docker/Dockerfile
Normal file
42
enclave/docker/Dockerfile
Normal file
@ -0,0 +1,42 @@
|
||||
FROM debian:buster-20191014
|
||||
|
||||
COPY apt.conf sources.list /etc/apt/
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -V -y --no-install-recommends --allow-downgrades \
|
||||
build-essential ca-certificates curl git cmake ninja-build \
|
||||
devscripts debhelper fakeroot libwww-perl gnupg \
|
||||
ocaml-native-compilers ocamlbuild automake autoconf libtool wget python pkg-config \
|
||||
libssl-dev libcurl4-openssl-dev protobuf-compiler libprotobuf-dev \
|
||||
llvm-dev libclang-dev clang \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
ARG UID
|
||||
ARG GID
|
||||
|
||||
#Create a user to map the host user to.
|
||||
RUN groupadd -o -g ${GID} signal \
|
||||
&& useradd -m -o -u ${UID} -g ${GID} -s /bin/bash signal \
|
||||
&& mkdir -p /tmp/docker \
|
||||
&& chown -R signal.signal /tmp/docker
|
||||
|
||||
USER signal
|
||||
ENV HOME /home/signal
|
||||
ENV USER signal
|
||||
ENV SHELL /bin/bash
|
||||
|
||||
WORKDIR /home/signal
|
||||
|
||||
ARG TOOLCHAIN=1.37.0
|
||||
|
||||
COPY rustup-init.sha256 /tmp/docker/
|
||||
|
||||
RUN curl -f https://static.rust-lang.org/rustup/archive/1.20.2/x86_64-unknown-linux-gnu/rustup-init -o /tmp/rustup-init \
|
||||
&& [ `sha256sum /tmp/rustup-init|cut -d' ' -f1` = `cut -d' ' -f1</tmp/docker/rustup-init.sha256` ] \
|
||||
&& chmod a+x /tmp/rustup-init \
|
||||
&& /tmp/rustup-init -y --profile minimal --component rustfmt --default-toolchain "${TOOLCHAIN}" \
|
||||
&& rm -rf /tmp/rustup-init /tmp/docker
|
||||
|
||||
ENV PATH="/home/signal/.cargo/bin:${PATH}"
|
||||
|
||||
CMD [ "/bin/bash" ]
|
||||
10
enclave/docker/apt.conf
Normal file
10
enclave/docker/apt.conf
Normal file
@ -0,0 +1,10 @@
|
||||
Apt {
|
||||
Architecture "amd64";
|
||||
Architectures "amd64";
|
||||
};
|
||||
|
||||
Acquire::Check-Valid-Until "false";
|
||||
Acquire::Languages "none";
|
||||
Binary::apt-get::Acquire::AllowInsecureRepositories "false";
|
||||
|
||||
APT::Install-Recommends "false";
|
||||
1
enclave/docker/rustup-init.sha256
Normal file
1
enclave/docker/rustup-init.sha256
Normal file
@ -0,0 +1 @@
|
||||
e68f193542c68ce83c449809d2cad262cc2bbb99640eb47c58fc1dc58cc30add *target/x86_64-unknown-linux-gnu/release/rustup-init
|
||||
2
enclave/docker/sources.list
Normal file
2
enclave/docker/sources.list
Normal file
@ -0,0 +1,2 @@
|
||||
deb http://snapshot.debian.org/archive/debian/20191014T000000Z/ buster main
|
||||
deb http://snapshot.debian.org/archive/debian-security/20191014T000000Z/ buster/updates main
|
||||
170
enclave/include/bearssl/bearssl.h
Normal file
170
enclave/include/bearssl/bearssl.h
Normal file
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef BR_BEARSSL_H__
|
||||
#define BR_BEARSSL_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/** \mainpage BearSSL API
|
||||
*
|
||||
* # API Layout
|
||||
*
|
||||
* The functions and structures defined by the BearSSL API are located
|
||||
* in various header files:
|
||||
*
|
||||
* | Header file | Elements |
|
||||
* | :-------------- | :------------------------------------------------ |
|
||||
* | bearssl_hash.h | Hash functions |
|
||||
* | bearssl_hmac.h | HMAC |
|
||||
* | bearssl_kdf.h | Key Derivation Functions |
|
||||
* | bearssl_rand.h | Pseudorandom byte generators |
|
||||
* | bearssl_prf.h | PRF implementations (for SSL/TLS) |
|
||||
* | bearssl_block.h | Symmetric encryption |
|
||||
* | bearssl_aead.h | AEAD algorithms (combined encryption + MAC) |
|
||||
* | bearssl_rsa.h | RSA encryption and signatures |
|
||||
* | bearssl_ec.h | Elliptic curves support (including ECDSA) |
|
||||
* | bearssl_ssl.h | SSL/TLS engine interface |
|
||||
* | bearssl_x509.h | X.509 certificate decoding and validation |
|
||||
* | bearssl_pem.h | Base64/PEM decoding support functions |
|
||||
*
|
||||
* Applications using BearSSL are supposed to simply include `bearssl.h`
|
||||
* as follows:
|
||||
*
|
||||
* #include <bearssl.h>
|
||||
*
|
||||
* The `bearssl.h` file itself includes all the other header files. It is
|
||||
* possible to include specific header files, but it has no practical
|
||||
* advantage for the application. The API is separated into separate
|
||||
* header files only for documentation convenience.
|
||||
*
|
||||
*
|
||||
* # Conventions
|
||||
*
|
||||
* ## MUST and SHALL
|
||||
*
|
||||
* In all descriptions, the usual "MUST", "SHALL", "MAY",... terminology
|
||||
* is used. Failure to meet requirements expressed with a "MUST" or
|
||||
* "SHALL" implies undefined behaviour, which means that segmentation
|
||||
* faults, buffer overflows, and other similar adverse events, may occur.
|
||||
*
|
||||
* In general, BearSSL is not very forgiving of programming errors, and
|
||||
* does not include much failsafes or error reporting when the problem
|
||||
* does not arise from external transient conditions, and can be fixed
|
||||
* only in the application code. This is done so in order to make the
|
||||
* total code footprint lighter.
|
||||
*
|
||||
*
|
||||
* ## `NULL` values
|
||||
*
|
||||
* Function parameters with a pointer type shall not be `NULL` unless
|
||||
* explicitly authorised by the documentation. As an exception, when
|
||||
* the pointer aims at a sequence of bytes and is accompanied with
|
||||
* a length parameter, and the length is zero (meaning that there is
|
||||
* no byte at all to retrieve), then the pointer may be `NULL` even if
|
||||
* not explicitly allowed.
|
||||
*
|
||||
*
|
||||
* ## Memory Allocation
|
||||
*
|
||||
* BearSSL does not perform dynamic memory allocation. This implies that
|
||||
* for any functionality that requires a non-transient state, the caller
|
||||
* is responsible for allocating the relevant context structure. Such
|
||||
* allocation can be done in any appropriate area, including static data
|
||||
* segments, the heap, and the stack, provided that proper alignment is
|
||||
* respected. The header files define these context structures
|
||||
* (including size and contents), so the C compiler should handle
|
||||
* alignment automatically.
|
||||
*
|
||||
* Since there is no dynamic resource allocation, there is also nothing to
|
||||
* release. When the calling code is done with a BearSSL feature, it
|
||||
* may simple release the context structures it allocated itself, with
|
||||
* no "close function" to call. If the context structures were allocated
|
||||
* on the stack (as local variables), then even that release operation is
|
||||
* implicit.
|
||||
*
|
||||
*
|
||||
* ## Structure Contents
|
||||
*
|
||||
* Except when explicitly indicated, structure contents are opaque: they
|
||||
* are included in the header files so that calling code may know the
|
||||
* structure sizes and alignment requirements, but callers SHALL NOT
|
||||
* access individual fields directly. For fields that are supposed to
|
||||
* be read from or written to, the API defines accessor functions (the
|
||||
* simplest of these accessor functions are defined as `static inline`
|
||||
* functions, and the C compiler will optimise them away).
|
||||
*
|
||||
*
|
||||
* # API Usage
|
||||
*
|
||||
* BearSSL usage for running a SSL/TLS client or server is described
|
||||
* on the [BearSSL Web site](https://www.bearssl.org/api1.html). The
|
||||
* BearSSL source archive also comes with sample code.
|
||||
*/
|
||||
|
||||
#include "bearssl_hash.h"
|
||||
#include "bearssl_hmac.h"
|
||||
#include "bearssl_kdf.h"
|
||||
#include "bearssl_rand.h"
|
||||
#include "bearssl_prf.h"
|
||||
#include "bearssl_block.h"
|
||||
#include "bearssl_aead.h"
|
||||
#include "bearssl_rsa.h"
|
||||
#include "bearssl_ec.h"
|
||||
#include "bearssl_ssl.h"
|
||||
#include "bearssl_x509.h"
|
||||
#include "bearssl_pem.h"
|
||||
|
||||
/** \brief Type for a configuration option.
|
||||
*
|
||||
* A "configuration option" is a value that is selected when the BearSSL
|
||||
* library itself is compiled. Most options are boolean; their value is
|
||||
* then either 1 (option is enabled) or 0 (option is disabled). Some
|
||||
* values have other integer values. Option names correspond to macro
|
||||
* names. Some of the options can be explicitly set in the internal
|
||||
* `"config.h"` file.
|
||||
*/
|
||||
typedef struct {
|
||||
/** \brief Configurable option name. */
|
||||
const char *name;
|
||||
/** \brief Configurable option value. */
|
||||
long value;
|
||||
} br_config_option;
|
||||
|
||||
/** \brief Get configuration report.
|
||||
*
|
||||
* This function returns compiled configuration options, each as a
|
||||
* 'long' value. Names match internal macro names, in particular those
|
||||
* that can be set in the `"config.h"` inner file. For boolean options,
|
||||
* the numerical value is 1 if enabled, 0 if disabled. For maximum
|
||||
* key sizes, values are expressed in bits.
|
||||
*
|
||||
* The returned array is terminated by an entry whose `name` is `NULL`.
|
||||
*
|
||||
* \return the configuration report.
|
||||
*/
|
||||
const br_config_option *br_get_config(void);
|
||||
|
||||
#endif
|
||||
1059
enclave/include/bearssl/bearssl_aead.h
Normal file
1059
enclave/include/bearssl/bearssl_aead.h
Normal file
File diff suppressed because it is too large
Load Diff
2618
enclave/include/bearssl/bearssl_block.h
Normal file
2618
enclave/include/bearssl/bearssl_block.h
Normal file
File diff suppressed because it is too large
Load Diff
967
enclave/include/bearssl/bearssl_ec.h
Normal file
967
enclave/include/bearssl/bearssl_ec.h
Normal file
@ -0,0 +1,967 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef BR_BEARSSL_EC_H__
|
||||
#define BR_BEARSSL_EC_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "bearssl_rand.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \file bearssl_ec.h
|
||||
*
|
||||
* # Elliptic Curves
|
||||
*
|
||||
* This file documents the EC implementations provided with BearSSL, and
|
||||
* ECDSA.
|
||||
*
|
||||
* ## Elliptic Curve API
|
||||
*
|
||||
* Only "named curves" are supported. Each EC implementation supports
|
||||
* one or several named curves, identified by symbolic identifiers.
|
||||
* These identifiers are small integers, that correspond to the values
|
||||
* registered by the
|
||||
* [IANA](http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8).
|
||||
*
|
||||
* Since all currently defined elliptic curve identifiers are in the 0..31
|
||||
* range, it is convenient to encode support of some curves in a 32-bit
|
||||
* word, such that bit x corresponds to curve of identifier x.
|
||||
*
|
||||
* An EC implementation is incarnated by a `br_ec_impl` instance, that
|
||||
* offers the following fields:
|
||||
*
|
||||
* - `supported_curves`
|
||||
*
|
||||
* A 32-bit word that documents the identifiers of the curves supported
|
||||
* by this implementation.
|
||||
*
|
||||
* - `generator()`
|
||||
*
|
||||
* Callback method that returns a pointer to the conventional generator
|
||||
* point for that curve.
|
||||
*
|
||||
* - `order()`
|
||||
*
|
||||
* Callback method that returns a pointer to the subgroup order for
|
||||
* that curve. That value uses unsigned big-endian encoding.
|
||||
*
|
||||
* - `xoff()`
|
||||
*
|
||||
* Callback method that returns the offset and length of the X
|
||||
* coordinate in an encoded point.
|
||||
*
|
||||
* - `mul()`
|
||||
*
|
||||
* Multiply a curve point with an integer.
|
||||
*
|
||||
* - `mulgen()`
|
||||
*
|
||||
* Multiply the curve generator with an integer. This may be faster
|
||||
* than the generic `mul()`.
|
||||
*
|
||||
* - `muladd()`
|
||||
*
|
||||
* Multiply two curve points by two integers, and return the sum of
|
||||
* the two products.
|
||||
*
|
||||
* All curve points are represented in uncompressed format. The `mul()`
|
||||
* and `muladd()` methods take care to validate that the provided points
|
||||
* are really part of the relevant curve subgroup.
|
||||
*
|
||||
* For all point multiplication functions, the following holds:
|
||||
*
|
||||
* - Functions validate that the provided points are valid members
|
||||
* of the relevant curve subgroup. An error is reported if that is
|
||||
* not the case.
|
||||
*
|
||||
* - Processing is constant-time, even if the point operands are not
|
||||
* valid. This holds for both the source and resulting points, and
|
||||
* the multipliers (integers). Only the byte length of the provided
|
||||
* multiplier arrays (not their actual value length in bits) may
|
||||
* leak through timing-based side channels.
|
||||
*
|
||||
* - The multipliers (integers) MUST be lower than the subgroup order.
|
||||
* If this property is not met, then the result is indeterminate,
|
||||
* but an error value is not ncessearily returned.
|
||||
*
|
||||
*
|
||||
* ## ECDSA
|
||||
*
|
||||
* ECDSA signatures have two standard formats, called "raw" and "asn1".
|
||||
* Internally, such a signature is a pair of modular integers `(r,s)`.
|
||||
* The "raw" format is the concatenation of the unsigned big-endian
|
||||
* encodings of these two integers, possibly left-padded with zeros so
|
||||
* that they have the same encoded length. The "asn1" format is the
|
||||
* DER encoding of an ASN.1 structure that contains the two integer
|
||||
* values:
|
||||
*
|
||||
* ECDSASignature ::= SEQUENCE {
|
||||
* r INTEGER,
|
||||
* s INTEGER
|
||||
* }
|
||||
*
|
||||
* In general, in all of X.509 and SSL/TLS, the "asn1" format is used.
|
||||
* BearSSL offers ECDSA implementations for both formats; conversion
|
||||
* functions between the two formats are also provided. Conversion of a
|
||||
* "raw" format signature into "asn1" may enlarge a signature by no more
|
||||
* than 9 bytes for all supported curves; conversely, conversion of an
|
||||
* "asn1" signature to "raw" may expand the signature but the "raw"
|
||||
* length will never be more than twice the length of the "asn1" length
|
||||
* (and usually it will be shorter).
|
||||
*
|
||||
* Note that for a given signature, the "raw" format is not fully
|
||||
* deterministic, in that it does not enforce a minimal common length.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Standard curve ID. These ID are equal to the assigned numerical
|
||||
* identifiers assigned to these curves for TLS:
|
||||
* http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8
|
||||
*/
|
||||
|
||||
/** \brief Identifier for named curve sect163k1. */
|
||||
#define BR_EC_sect163k1 1
|
||||
|
||||
/** \brief Identifier for named curve sect163r1. */
|
||||
#define BR_EC_sect163r1 2
|
||||
|
||||
/** \brief Identifier for named curve sect163r2. */
|
||||
#define BR_EC_sect163r2 3
|
||||
|
||||
/** \brief Identifier for named curve sect193r1. */
|
||||
#define BR_EC_sect193r1 4
|
||||
|
||||
/** \brief Identifier for named curve sect193r2. */
|
||||
#define BR_EC_sect193r2 5
|
||||
|
||||
/** \brief Identifier for named curve sect233k1. */
|
||||
#define BR_EC_sect233k1 6
|
||||
|
||||
/** \brief Identifier for named curve sect233r1. */
|
||||
#define BR_EC_sect233r1 7
|
||||
|
||||
/** \brief Identifier for named curve sect239k1. */
|
||||
#define BR_EC_sect239k1 8
|
||||
|
||||
/** \brief Identifier for named curve sect283k1. */
|
||||
#define BR_EC_sect283k1 9
|
||||
|
||||
/** \brief Identifier for named curve sect283r1. */
|
||||
#define BR_EC_sect283r1 10
|
||||
|
||||
/** \brief Identifier for named curve sect409k1. */
|
||||
#define BR_EC_sect409k1 11
|
||||
|
||||
/** \brief Identifier for named curve sect409r1. */
|
||||
#define BR_EC_sect409r1 12
|
||||
|
||||
/** \brief Identifier for named curve sect571k1. */
|
||||
#define BR_EC_sect571k1 13
|
||||
|
||||
/** \brief Identifier for named curve sect571r1. */
|
||||
#define BR_EC_sect571r1 14
|
||||
|
||||
/** \brief Identifier for named curve secp160k1. */
|
||||
#define BR_EC_secp160k1 15
|
||||
|
||||
/** \brief Identifier for named curve secp160r1. */
|
||||
#define BR_EC_secp160r1 16
|
||||
|
||||
/** \brief Identifier for named curve secp160r2. */
|
||||
#define BR_EC_secp160r2 17
|
||||
|
||||
/** \brief Identifier for named curve secp192k1. */
|
||||
#define BR_EC_secp192k1 18
|
||||
|
||||
/** \brief Identifier for named curve secp192r1. */
|
||||
#define BR_EC_secp192r1 19
|
||||
|
||||
/** \brief Identifier for named curve secp224k1. */
|
||||
#define BR_EC_secp224k1 20
|
||||
|
||||
/** \brief Identifier for named curve secp224r1. */
|
||||
#define BR_EC_secp224r1 21
|
||||
|
||||
/** \brief Identifier for named curve secp256k1. */
|
||||
#define BR_EC_secp256k1 22
|
||||
|
||||
/** \brief Identifier for named curve secp256r1. */
|
||||
#define BR_EC_secp256r1 23
|
||||
|
||||
/** \brief Identifier for named curve secp384r1. */
|
||||
#define BR_EC_secp384r1 24
|
||||
|
||||
/** \brief Identifier for named curve secp521r1. */
|
||||
#define BR_EC_secp521r1 25
|
||||
|
||||
/** \brief Identifier for named curve brainpoolP256r1. */
|
||||
#define BR_EC_brainpoolP256r1 26
|
||||
|
||||
/** \brief Identifier for named curve brainpoolP384r1. */
|
||||
#define BR_EC_brainpoolP384r1 27
|
||||
|
||||
/** \brief Identifier for named curve brainpoolP512r1. */
|
||||
#define BR_EC_brainpoolP512r1 28
|
||||
|
||||
/** \brief Identifier for named curve Curve25519. */
|
||||
#define BR_EC_curve25519 29
|
||||
|
||||
/** \brief Identifier for named curve Curve448. */
|
||||
#define BR_EC_curve448 30
|
||||
|
||||
/**
|
||||
* \brief Structure for an EC public key.
|
||||
*/
|
||||
typedef struct {
|
||||
/** \brief Identifier for the curve used by this key. */
|
||||
int curve;
|
||||
/** \brief Public curve point (uncompressed format). */
|
||||
unsigned char *q;
|
||||
/** \brief Length of public curve point (in bytes). */
|
||||
size_t qlen;
|
||||
} br_ec_public_key;
|
||||
|
||||
/**
|
||||
* \brief Structure for an EC private key.
|
||||
*
|
||||
* The private key is an integer modulo the curve subgroup order. The
|
||||
* encoding below tolerates extra leading zeros. In general, it is
|
||||
* recommended that the private key has the same length as the curve
|
||||
* subgroup order.
|
||||
*/
|
||||
typedef struct {
|
||||
/** \brief Identifier for the curve used by this key. */
|
||||
int curve;
|
||||
/** \brief Private key (integer, unsigned big-endian encoding). */
|
||||
unsigned char *x;
|
||||
/** \brief Private key length (in bytes). */
|
||||
size_t xlen;
|
||||
} br_ec_private_key;
|
||||
|
||||
/**
|
||||
* \brief Type for an EC implementation.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* \brief Supported curves.
|
||||
*
|
||||
* This word is a bitfield: bit `x` is set if the curve of ID `x`
|
||||
* is supported. E.g. an implementation supporting both NIST P-256
|
||||
* (secp256r1, ID 23) and NIST P-384 (secp384r1, ID 24) will have
|
||||
* value `0x01800000` in this field.
|
||||
*/
|
||||
uint32_t supported_curves;
|
||||
|
||||
/**
|
||||
* \brief Get the conventional generator.
|
||||
*
|
||||
* This function returns the conventional generator (encoded
|
||||
* curve point) for the specified curve. This function MUST NOT
|
||||
* be called if the curve is not supported.
|
||||
*
|
||||
* \param curve curve identifier.
|
||||
* \param len receiver for the encoded generator length (in bytes).
|
||||
* \return the encoded generator.
|
||||
*/
|
||||
const unsigned char *(*generator)(int curve, size_t *len);
|
||||
|
||||
/**
|
||||
* \brief Get the subgroup order.
|
||||
*
|
||||
* This function returns the order of the subgroup generated by
|
||||
* the conventional generator, for the specified curve. Unsigned
|
||||
* big-endian encoding is used. This function MUST NOT be called
|
||||
* if the curve is not supported.
|
||||
*
|
||||
* \param curve curve identifier.
|
||||
* \param len receiver for the encoded order length (in bytes).
|
||||
* \return the encoded order.
|
||||
*/
|
||||
const unsigned char *(*order)(int curve, size_t *len);
|
||||
|
||||
/**
|
||||
* \brief Get the offset and length for the X coordinate.
|
||||
*
|
||||
* This function returns the offset and length (in bytes) of
|
||||
* the X coordinate in an encoded non-zero point.
|
||||
*
|
||||
* \param curve curve identifier.
|
||||
* \param len receiver for the X coordinate length (in bytes).
|
||||
* \return the offset for the X coordinate (in bytes).
|
||||
*/
|
||||
size_t (*xoff)(int curve, size_t *len);
|
||||
|
||||
/**
|
||||
* \brief Multiply a curve point by an integer.
|
||||
*
|
||||
* The source point is provided in array `G` (of size `Glen` bytes);
|
||||
* the multiplication result is written over it. The multiplier
|
||||
* `x` (of size `xlen` bytes) uses unsigned big-endian encoding.
|
||||
*
|
||||
* Rules:
|
||||
*
|
||||
* - The specified curve MUST be supported.
|
||||
*
|
||||
* - The source point must be a valid point on the relevant curve
|
||||
* subgroup (and not the "point at infinity" either). If this is
|
||||
* not the case, then this function returns an error (0).
|
||||
*
|
||||
* - The multiplier integer MUST be non-zero and less than the
|
||||
* curve subgroup order. If this property does not hold, then
|
||||
* the result is indeterminate and an error code is not
|
||||
* guaranteed.
|
||||
*
|
||||
* Returned value is 1 on success, 0 on error. On error, the
|
||||
* contents of `G` are indeterminate.
|
||||
*
|
||||
* \param G point to multiply.
|
||||
* \param Glen length of the encoded point (in bytes).
|
||||
* \param x multiplier (unsigned big-endian).
|
||||
* \param xlen multiplier length (in bytes).
|
||||
* \param curve curve identifier.
|
||||
* \return 1 on success, 0 on error.
|
||||
*/
|
||||
uint32_t (*mul)(unsigned char *G, size_t Glen,
|
||||
const unsigned char *x, size_t xlen, int curve);
|
||||
|
||||
/**
|
||||
* \brief Multiply the generator by an integer.
|
||||
*
|
||||
* The multiplier MUST be non-zero and less than the curve
|
||||
* subgroup order. Results are indeterminate if this property
|
||||
* does not hold.
|
||||
*
|
||||
* \param R output buffer for the point.
|
||||
* \param x multiplier (unsigned big-endian).
|
||||
* \param xlen multiplier length (in bytes).
|
||||
* \param curve curve identifier.
|
||||
* \return encoded result point length (in bytes).
|
||||
*/
|
||||
size_t (*mulgen)(unsigned char *R,
|
||||
const unsigned char *x, size_t xlen, int curve);
|
||||
|
||||
/**
|
||||
* \brief Multiply two points by two integers and add the
|
||||
* results.
|
||||
*
|
||||
* The point `x*A + y*B` is computed and written back in the `A`
|
||||
* array.
|
||||
*
|
||||
* Rules:
|
||||
*
|
||||
* - The specified curve MUST be supported.
|
||||
*
|
||||
* - The source points (`A` and `B`) must be valid points on
|
||||
* the relevant curve subgroup (and not the "point at
|
||||
* infinity" either). If this is not the case, then this
|
||||
* function returns an error (0).
|
||||
*
|
||||
* - If the `B` pointer is `NULL`, then the conventional
|
||||
* subgroup generator is used. With some implementations,
|
||||
* this may be faster than providing a pointer to the
|
||||
* generator.
|
||||
*
|
||||
* - The multiplier integers (`x` and `y`) MUST be non-zero
|
||||
* and less than the curve subgroup order. If either integer
|
||||
* is zero, then an error is reported, but if one of them is
|
||||
* not lower than the subgroup order, then the result is
|
||||
* indeterminate and an error code is not guaranteed.
|
||||
*
|
||||
* - If the final result is the point at infinity, then an
|
||||
* error is returned.
|
||||
*
|
||||
* Returned value is 1 on success, 0 on error. On error, the
|
||||
* contents of `A` are indeterminate.
|
||||
*
|
||||
* \param A first point to multiply.
|
||||
* \param B second point to multiply (`NULL` for the generator).
|
||||
* \param len common length of the encoded points (in bytes).
|
||||
* \param x multiplier for `A` (unsigned big-endian).
|
||||
* \param xlen length of multiplier for `A` (in bytes).
|
||||
* \param y multiplier for `A` (unsigned big-endian).
|
||||
* \param ylen length of multiplier for `A` (in bytes).
|
||||
* \param curve curve identifier.
|
||||
* \return 1 on success, 0 on error.
|
||||
*/
|
||||
uint32_t (*muladd)(unsigned char *A, const unsigned char *B, size_t len,
|
||||
const unsigned char *x, size_t xlen,
|
||||
const unsigned char *y, size_t ylen, int curve);
|
||||
} br_ec_impl;
|
||||
|
||||
/**
|
||||
* \brief EC implementation "i31".
|
||||
*
|
||||
* This implementation internally uses generic code for modular integers,
|
||||
* with a representation as sequences of 31-bit words. It supports secp256r1,
|
||||
* secp384r1 and secp521r1 (aka NIST curves P-256, P-384 and P-521).
|
||||
*/
|
||||
extern const br_ec_impl br_ec_prime_i31;
|
||||
|
||||
/**
|
||||
* \brief EC implementation "i15".
|
||||
*
|
||||
* This implementation internally uses generic code for modular integers,
|
||||
* with a representation as sequences of 15-bit words. It supports secp256r1,
|
||||
* secp384r1 and secp521r1 (aka NIST curves P-256, P-384 and P-521).
|
||||
*/
|
||||
extern const br_ec_impl br_ec_prime_i15;
|
||||
|
||||
/**
|
||||
* \brief EC implementation "m15" for P-256.
|
||||
*
|
||||
* This implementation uses specialised code for curve secp256r1 (also
|
||||
* known as NIST P-256), with optional Karatsuba decomposition, and fast
|
||||
* modular reduction thanks to the field modulus special format. Only
|
||||
* 32-bit multiplications are used (with 32-bit results, not 64-bit).
|
||||
*/
|
||||
extern const br_ec_impl br_ec_p256_m15;
|
||||
|
||||
/**
|
||||
* \brief EC implementation "m31" for P-256.
|
||||
*
|
||||
* This implementation uses specialised code for curve secp256r1 (also
|
||||
* known as NIST P-256), relying on multiplications of 31-bit values
|
||||
* (MUL31).
|
||||
*/
|
||||
extern const br_ec_impl br_ec_p256_m31;
|
||||
|
||||
/**
|
||||
* \brief EC implementation "m62" (specialised code) for P-256.
|
||||
*
|
||||
* This implementation uses custom code relying on multiplication of
|
||||
* integers up to 64 bits, with a 128-bit result. This implementation is
|
||||
* defined only on platforms that offer the 64x64->128 multiplication
|
||||
* support; use `br_ec_p256_m62_get()` to dynamically obtain a pointer
|
||||
* to that implementation.
|
||||
*/
|
||||
extern const br_ec_impl br_ec_p256_m62;
|
||||
|
||||
/**
|
||||
* \brief Get the "m62" implementation of P-256, if available.
|
||||
*
|
||||
* \return the implementation, or 0.
|
||||
*/
|
||||
const br_ec_impl *br_ec_p256_m62_get(void);
|
||||
|
||||
/**
|
||||
* \brief EC implementation "m64" (specialised code) for P-256.
|
||||
*
|
||||
* This implementation uses custom code relying on multiplication of
|
||||
* integers up to 64 bits, with a 128-bit result. This implementation is
|
||||
* defined only on platforms that offer the 64x64->128 multiplication
|
||||
* support; use `br_ec_p256_m64_get()` to dynamically obtain a pointer
|
||||
* to that implementation.
|
||||
*/
|
||||
extern const br_ec_impl br_ec_p256_m64;
|
||||
|
||||
/**
|
||||
* \brief Get the "m64" implementation of P-256, if available.
|
||||
*
|
||||
* \return the implementation, or 0.
|
||||
*/
|
||||
const br_ec_impl *br_ec_p256_m64_get(void);
|
||||
|
||||
/**
|
||||
* \brief EC implementation "i15" (generic code) for Curve25519.
|
||||
*
|
||||
* This implementation uses the generic code for modular integers (with
|
||||
* 15-bit words) to support Curve25519. Due to the specificities of the
|
||||
* curve definition, the following applies:
|
||||
*
|
||||
* - `muladd()` is not implemented (the function returns 0 systematically).
|
||||
* - `order()` returns 2^255-1, since the point multiplication algorithm
|
||||
* accepts any 32-bit integer as input (it clears the top bit and low
|
||||
* three bits systematically).
|
||||
*/
|
||||
extern const br_ec_impl br_ec_c25519_i15;
|
||||
|
||||
/**
|
||||
* \brief EC implementation "i31" (generic code) for Curve25519.
|
||||
*
|
||||
* This implementation uses the generic code for modular integers (with
|
||||
* 31-bit words) to support Curve25519. Due to the specificities of the
|
||||
* curve definition, the following applies:
|
||||
*
|
||||
* - `muladd()` is not implemented (the function returns 0 systematically).
|
||||
* - `order()` returns 2^255-1, since the point multiplication algorithm
|
||||
* accepts any 32-bit integer as input (it clears the top bit and low
|
||||
* three bits systematically).
|
||||
*/
|
||||
extern const br_ec_impl br_ec_c25519_i31;
|
||||
|
||||
/**
|
||||
* \brief EC implementation "m15" (specialised code) for Curve25519.
|
||||
*
|
||||
* This implementation uses custom code relying on multiplication of
|
||||
* integers up to 15 bits. Due to the specificities of the curve
|
||||
* definition, the following applies:
|
||||
*
|
||||
* - `muladd()` is not implemented (the function returns 0 systematically).
|
||||
* - `order()` returns 2^255-1, since the point multiplication algorithm
|
||||
* accepts any 32-bit integer as input (it clears the top bit and low
|
||||
* three bits systematically).
|
||||
*/
|
||||
extern const br_ec_impl br_ec_c25519_m15;
|
||||
|
||||
/**
|
||||
* \brief EC implementation "m31" (specialised code) for Curve25519.
|
||||
*
|
||||
* This implementation uses custom code relying on multiplication of
|
||||
* integers up to 31 bits. Due to the specificities of the curve
|
||||
* definition, the following applies:
|
||||
*
|
||||
* - `muladd()` is not implemented (the function returns 0 systematically).
|
||||
* - `order()` returns 2^255-1, since the point multiplication algorithm
|
||||
* accepts any 32-bit integer as input (it clears the top bit and low
|
||||
* three bits systematically).
|
||||
*/
|
||||
extern const br_ec_impl br_ec_c25519_m31;
|
||||
|
||||
/**
|
||||
* \brief EC implementation "m62" (specialised code) for Curve25519.
|
||||
*
|
||||
* This implementation uses custom code relying on multiplication of
|
||||
* integers up to 62 bits, with a 124-bit result. This implementation is
|
||||
* defined only on platforms that offer the 64x64->128 multiplication
|
||||
* support; use `br_ec_c25519_m62_get()` to dynamically obtain a pointer
|
||||
* to that implementation. Due to the specificities of the curve
|
||||
* definition, the following applies:
|
||||
*
|
||||
* - `muladd()` is not implemented (the function returns 0 systematically).
|
||||
* - `order()` returns 2^255-1, since the point multiplication algorithm
|
||||
* accepts any 32-bit integer as input (it clears the top bit and low
|
||||
* three bits systematically).
|
||||
*/
|
||||
extern const br_ec_impl br_ec_c25519_m62;
|
||||
|
||||
/**
|
||||
* \brief Get the "m62" implementation of Curve25519, if available.
|
||||
*
|
||||
* \return the implementation, or 0.
|
||||
*/
|
||||
const br_ec_impl *br_ec_c25519_m62_get(void);
|
||||
|
||||
/**
|
||||
* \brief EC implementation "m64" (specialised code) for Curve25519.
|
||||
*
|
||||
* This implementation uses custom code relying on multiplication of
|
||||
* integers up to 64 bits, with a 128-bit result. This implementation is
|
||||
* defined only on platforms that offer the 64x64->128 multiplication
|
||||
* support; use `br_ec_c25519_m64_get()` to dynamically obtain a pointer
|
||||
* to that implementation. Due to the specificities of the curve
|
||||
* definition, the following applies:
|
||||
*
|
||||
* - `muladd()` is not implemented (the function returns 0 systematically).
|
||||
* - `order()` returns 2^255-1, since the point multiplication algorithm
|
||||
* accepts any 32-bit integer as input (it clears the top bit and low
|
||||
* three bits systematically).
|
||||
*/
|
||||
extern const br_ec_impl br_ec_c25519_m64;
|
||||
|
||||
/**
|
||||
* \brief Get the "m64" implementation of Curve25519, if available.
|
||||
*
|
||||
* \return the implementation, or 0.
|
||||
*/
|
||||
const br_ec_impl *br_ec_c25519_m64_get(void);
|
||||
|
||||
/**
|
||||
* \brief Aggregate EC implementation "m15".
|
||||
*
|
||||
* This implementation is a wrapper for:
|
||||
*
|
||||
* - `br_ec_c25519_m15` for Curve25519
|
||||
* - `br_ec_p256_m15` for NIST P-256
|
||||
* - `br_ec_prime_i15` for other curves (NIST P-384 and NIST-P512)
|
||||
*/
|
||||
extern const br_ec_impl br_ec_all_m15;
|
||||
|
||||
/**
|
||||
* \brief Aggregate EC implementation "m31".
|
||||
*
|
||||
* This implementation is a wrapper for:
|
||||
*
|
||||
* - `br_ec_c25519_m31` for Curve25519
|
||||
* - `br_ec_p256_m31` for NIST P-256
|
||||
* - `br_ec_prime_i31` for other curves (NIST P-384 and NIST-P512)
|
||||
*/
|
||||
extern const br_ec_impl br_ec_all_m31;
|
||||
|
||||
/**
|
||||
* \brief Get the "default" EC implementation for the current system.
|
||||
*
|
||||
* This returns a pointer to the preferred implementation on the
|
||||
* current system.
|
||||
*
|
||||
* \return the default EC implementation.
|
||||
*/
|
||||
const br_ec_impl *br_ec_get_default(void);
|
||||
|
||||
/**
|
||||
* \brief Convert a signature from "raw" to "asn1".
|
||||
*
|
||||
* Conversion is done "in place" and the new length is returned.
|
||||
* Conversion may enlarge the signature, but by no more than 9 bytes at
|
||||
* most. On error, 0 is returned (error conditions include an odd raw
|
||||
* signature length, or an oversized integer).
|
||||
*
|
||||
* \param sig signature to convert.
|
||||
* \param sig_len signature length (in bytes).
|
||||
* \return the new signature length, or 0 on error.
|
||||
*/
|
||||
size_t br_ecdsa_raw_to_asn1(void *sig, size_t sig_len);
|
||||
|
||||
/**
|
||||
* \brief Convert a signature from "asn1" to "raw".
|
||||
*
|
||||
* Conversion is done "in place" and the new length is returned.
|
||||
* Conversion may enlarge the signature, but the new signature length
|
||||
* will be less than twice the source length at most. On error, 0 is
|
||||
* returned (error conditions include an invalid ASN.1 structure or an
|
||||
* oversized integer).
|
||||
*
|
||||
* \param sig signature to convert.
|
||||
* \param sig_len signature length (in bytes).
|
||||
* \return the new signature length, or 0 on error.
|
||||
*/
|
||||
size_t br_ecdsa_asn1_to_raw(void *sig, size_t sig_len);
|
||||
|
||||
/**
|
||||
* \brief Type for an ECDSA signer function.
|
||||
*
|
||||
* A pointer to the EC implementation is provided. The hash value is
|
||||
* assumed to have the length inferred from the designated hash function
|
||||
* class.
|
||||
*
|
||||
* Signature is written in the buffer pointed to by `sig`, and the length
|
||||
* (in bytes) is returned. On error, nothing is written in the buffer,
|
||||
* and 0 is returned. This function returns 0 if the specified curve is
|
||||
* not supported by the provided EC implementation.
|
||||
*
|
||||
* The signature format is either "raw" or "asn1", depending on the
|
||||
* implementation; maximum length is predictable from the implemented
|
||||
* curve:
|
||||
*
|
||||
* | curve | raw | asn1 |
|
||||
* | :--------- | --: | ---: |
|
||||
* | NIST P-256 | 64 | 72 |
|
||||
* | NIST P-384 | 96 | 104 |
|
||||
* | NIST P-521 | 132 | 139 |
|
||||
*
|
||||
* \param impl EC implementation to use.
|
||||
* \param hf hash function used to process the data.
|
||||
* \param hash_value signed data (hashed).
|
||||
* \param sk EC private key.
|
||||
* \param sig destination buffer.
|
||||
* \return the signature length (in bytes), or 0 on error.
|
||||
*/
|
||||
typedef size_t (*br_ecdsa_sign)(const br_ec_impl *impl,
|
||||
const br_hash_class *hf, const void *hash_value,
|
||||
const br_ec_private_key *sk, void *sig);
|
||||
|
||||
/**
|
||||
* \brief Type for an ECDSA signature verification function.
|
||||
*
|
||||
* A pointer to the EC implementation is provided. The hashed value,
|
||||
* computed over the purportedly signed data, is also provided with
|
||||
* its length.
|
||||
*
|
||||
* The signature format is either "raw" or "asn1", depending on the
|
||||
* implementation.
|
||||
*
|
||||
* Returned value is 1 on success (valid signature), 0 on error. This
|
||||
* function returns 0 if the specified curve is not supported by the
|
||||
* provided EC implementation.
|
||||
*
|
||||
* \param impl EC implementation to use.
|
||||
* \param hash signed data (hashed).
|
||||
* \param hash_len hash value length (in bytes).
|
||||
* \param pk EC public key.
|
||||
* \param sig signature.
|
||||
* \param sig_len signature length (in bytes).
|
||||
* \return 1 on success, 0 on error.
|
||||
*/
|
||||
typedef uint32_t (*br_ecdsa_vrfy)(const br_ec_impl *impl,
|
||||
const void *hash, size_t hash_len,
|
||||
const br_ec_public_key *pk, const void *sig, size_t sig_len);
|
||||
|
||||
/**
|
||||
* \brief ECDSA signature generator, "i31" implementation, "asn1" format.
|
||||
*
|
||||
* \see br_ecdsa_sign()
|
||||
*
|
||||
* \param impl EC implementation to use.
|
||||
* \param hf hash function used to process the data.
|
||||
* \param hash_value signed data (hashed).
|
||||
* \param sk EC private key.
|
||||
* \param sig destination buffer.
|
||||
* \return the signature length (in bytes), or 0 on error.
|
||||
*/
|
||||
size_t br_ecdsa_i31_sign_asn1(const br_ec_impl *impl,
|
||||
const br_hash_class *hf, const void *hash_value,
|
||||
const br_ec_private_key *sk, void *sig);
|
||||
|
||||
/**
|
||||
* \brief ECDSA signature generator, "i31" implementation, "raw" format.
|
||||
*
|
||||
* \see br_ecdsa_sign()
|
||||
*
|
||||
* \param impl EC implementation to use.
|
||||
* \param hf hash function used to process the data.
|
||||
* \param hash_value signed data (hashed).
|
||||
* \param sk EC private key.
|
||||
* \param sig destination buffer.
|
||||
* \return the signature length (in bytes), or 0 on error.
|
||||
*/
|
||||
size_t br_ecdsa_i31_sign_raw(const br_ec_impl *impl,
|
||||
const br_hash_class *hf, const void *hash_value,
|
||||
const br_ec_private_key *sk, void *sig);
|
||||
|
||||
/**
|
||||
* \brief ECDSA signature verifier, "i31" implementation, "asn1" format.
|
||||
*
|
||||
* \see br_ecdsa_vrfy()
|
||||
*
|
||||
* \param impl EC implementation to use.
|
||||
* \param hash signed data (hashed).
|
||||
* \param hash_len hash value length (in bytes).
|
||||
* \param pk EC public key.
|
||||
* \param sig signature.
|
||||
* \param sig_len signature length (in bytes).
|
||||
* \return 1 on success, 0 on error.
|
||||
*/
|
||||
uint32_t br_ecdsa_i31_vrfy_asn1(const br_ec_impl *impl,
|
||||
const void *hash, size_t hash_len,
|
||||
const br_ec_public_key *pk, const void *sig, size_t sig_len);
|
||||
|
||||
/**
|
||||
* \brief ECDSA signature verifier, "i31" implementation, "raw" format.
|
||||
*
|
||||
* \see br_ecdsa_vrfy()
|
||||
*
|
||||
* \param impl EC implementation to use.
|
||||
* \param hash signed data (hashed).
|
||||
* \param hash_len hash value length (in bytes).
|
||||
* \param pk EC public key.
|
||||
* \param sig signature.
|
||||
* \param sig_len signature length (in bytes).
|
||||
* \return 1 on success, 0 on error.
|
||||
*/
|
||||
uint32_t br_ecdsa_i31_vrfy_raw(const br_ec_impl *impl,
|
||||
const void *hash, size_t hash_len,
|
||||
const br_ec_public_key *pk, const void *sig, size_t sig_len);
|
||||
|
||||
/**
|
||||
* \brief ECDSA signature generator, "i15" implementation, "asn1" format.
|
||||
*
|
||||
* \see br_ecdsa_sign()
|
||||
*
|
||||
* \param impl EC implementation to use.
|
||||
* \param hf hash function used to process the data.
|
||||
* \param hash_value signed data (hashed).
|
||||
* \param sk EC private key.
|
||||
* \param sig destination buffer.
|
||||
* \return the signature length (in bytes), or 0 on error.
|
||||
*/
|
||||
size_t br_ecdsa_i15_sign_asn1(const br_ec_impl *impl,
|
||||
const br_hash_class *hf, const void *hash_value,
|
||||
const br_ec_private_key *sk, void *sig);
|
||||
|
||||
/**
|
||||
* \brief ECDSA signature generator, "i15" implementation, "raw" format.
|
||||
*
|
||||
* \see br_ecdsa_sign()
|
||||
*
|
||||
* \param impl EC implementation to use.
|
||||
* \param hf hash function used to process the data.
|
||||
* \param hash_value signed data (hashed).
|
||||
* \param sk EC private key.
|
||||
* \param sig destination buffer.
|
||||
* \return the signature length (in bytes), or 0 on error.
|
||||
*/
|
||||
size_t br_ecdsa_i15_sign_raw(const br_ec_impl *impl,
|
||||
const br_hash_class *hf, const void *hash_value,
|
||||
const br_ec_private_key *sk, void *sig);
|
||||
|
||||
/**
|
||||
* \brief ECDSA signature verifier, "i15" implementation, "asn1" format.
|
||||
*
|
||||
* \see br_ecdsa_vrfy()
|
||||
*
|
||||
* \param impl EC implementation to use.
|
||||
* \param hash signed data (hashed).
|
||||
* \param hash_len hash value length (in bytes).
|
||||
* \param pk EC public key.
|
||||
* \param sig signature.
|
||||
* \param sig_len signature length (in bytes).
|
||||
* \return 1 on success, 0 on error.
|
||||
*/
|
||||
uint32_t br_ecdsa_i15_vrfy_asn1(const br_ec_impl *impl,
|
||||
const void *hash, size_t hash_len,
|
||||
const br_ec_public_key *pk, const void *sig, size_t sig_len);
|
||||
|
||||
/**
|
||||
* \brief ECDSA signature verifier, "i15" implementation, "raw" format.
|
||||
*
|
||||
* \see br_ecdsa_vrfy()
|
||||
*
|
||||
* \param impl EC implementation to use.
|
||||
* \param hash signed data (hashed).
|
||||
* \param hash_len hash value length (in bytes).
|
||||
* \param pk EC public key.
|
||||
* \param sig signature.
|
||||
* \param sig_len signature length (in bytes).
|
||||
* \return 1 on success, 0 on error.
|
||||
*/
|
||||
uint32_t br_ecdsa_i15_vrfy_raw(const br_ec_impl *impl,
|
||||
const void *hash, size_t hash_len,
|
||||
const br_ec_public_key *pk, const void *sig, size_t sig_len);
|
||||
|
||||
/**
|
||||
* \brief Get "default" ECDSA implementation (signer, asn1 format).
|
||||
*
|
||||
* This returns the preferred implementation of ECDSA signature generation
|
||||
* ("asn1" output format) on the current system.
|
||||
*
|
||||
* \return the default implementation.
|
||||
*/
|
||||
br_ecdsa_sign br_ecdsa_sign_asn1_get_default(void);
|
||||
|
||||
/**
|
||||
* \brief Get "default" ECDSA implementation (signer, raw format).
|
||||
*
|
||||
* This returns the preferred implementation of ECDSA signature generation
|
||||
* ("raw" output format) on the current system.
|
||||
*
|
||||
* \return the default implementation.
|
||||
*/
|
||||
br_ecdsa_sign br_ecdsa_sign_raw_get_default(void);
|
||||
|
||||
/**
|
||||
* \brief Get "default" ECDSA implementation (verifier, asn1 format).
|
||||
*
|
||||
* This returns the preferred implementation of ECDSA signature verification
|
||||
* ("asn1" output format) on the current system.
|
||||
*
|
||||
* \return the default implementation.
|
||||
*/
|
||||
br_ecdsa_vrfy br_ecdsa_vrfy_asn1_get_default(void);
|
||||
|
||||
/**
|
||||
* \brief Get "default" ECDSA implementation (verifier, raw format).
|
||||
*
|
||||
* This returns the preferred implementation of ECDSA signature verification
|
||||
* ("raw" output format) on the current system.
|
||||
*
|
||||
* \return the default implementation.
|
||||
*/
|
||||
br_ecdsa_vrfy br_ecdsa_vrfy_raw_get_default(void);
|
||||
|
||||
/**
|
||||
* \brief Maximum size for EC private key element buffer.
|
||||
*
|
||||
* This is the largest number of bytes that `br_ec_keygen()` may need or
|
||||
* ever return.
|
||||
*/
|
||||
#define BR_EC_KBUF_PRIV_MAX_SIZE 72
|
||||
|
||||
/**
|
||||
* \brief Maximum size for EC public key element buffer.
|
||||
*
|
||||
* This is the largest number of bytes that `br_ec_compute_public()` may
|
||||
* need or ever return.
|
||||
*/
|
||||
#define BR_EC_KBUF_PUB_MAX_SIZE 145
|
||||
|
||||
/**
|
||||
* \brief Generate a new EC private key.
|
||||
*
|
||||
* If the specified `curve` is not supported by the elliptic curve
|
||||
* implementation (`impl`), then this function returns zero.
|
||||
*
|
||||
* The `sk` structure fields are set to the new private key data. In
|
||||
* particular, `sk.x` is made to point to the provided key buffer (`kbuf`),
|
||||
* in which the actual private key data is written. That buffer is assumed
|
||||
* to be large enough. The `BR_EC_KBUF_PRIV_MAX_SIZE` defines the maximum
|
||||
* size for all supported curves.
|
||||
*
|
||||
* The number of bytes used in `kbuf` is returned. If `kbuf` is `NULL`, then
|
||||
* the private key is not actually generated, and `sk` may also be `NULL`;
|
||||
* the minimum length for `kbuf` is still computed and returned.
|
||||
*
|
||||
* If `sk` is `NULL` but `kbuf` is not `NULL`, then the private key is
|
||||
* still generated and stored in `kbuf`.
|
||||
*
|
||||
* \param rng_ctx source PRNG context (already initialized).
|
||||
* \param impl the elliptic curve implementation.
|
||||
* \param sk the private key structure to fill, or `NULL`.
|
||||
* \param kbuf the key element buffer, or `NULL`.
|
||||
* \param curve the curve identifier.
|
||||
* \return the key data length (in bytes), or zero.
|
||||
*/
|
||||
size_t br_ec_keygen(const br_prng_class **rng_ctx,
|
||||
const br_ec_impl *impl, br_ec_private_key *sk,
|
||||
void *kbuf, int curve);
|
||||
|
||||
/**
|
||||
* \brief Compute EC public key from EC private key.
|
||||
*
|
||||
* This function uses the provided elliptic curve implementation (`impl`)
|
||||
* to compute the public key corresponding to the private key held in `sk`.
|
||||
* The public key point is written into `kbuf`, which is then linked from
|
||||
* the `*pk` structure. The size of the public key point, i.e. the number
|
||||
* of bytes used in `kbuf`, is returned.
|
||||
*
|
||||
* If `kbuf` is `NULL`, then the public key point is NOT computed, and
|
||||
* the public key structure `*pk` is unmodified (`pk` may be `NULL` in
|
||||
* that case). The size of the public key point is still returned.
|
||||
*
|
||||
* If `pk` is `NULL` but `kbuf` is not `NULL`, then the public key
|
||||
* point is computed and stored in `kbuf`, and its size is returned.
|
||||
*
|
||||
* If the curve used by the private key is not supported by the curve
|
||||
* implementation, then this function returns zero.
|
||||
*
|
||||
* The private key MUST be valid. An off-range private key value is not
|
||||
* necessarily detected, and leads to unpredictable results.
|
||||
*
|
||||
* \param impl the elliptic curve implementation.
|
||||
* \param pk the public key structure to fill (or `NULL`).
|
||||
* \param kbuf the public key point buffer (or `NULL`).
|
||||
* \param sk the source private key.
|
||||
* \return the public key point length (in bytes), or zero.
|
||||
*/
|
||||
size_t br_ec_compute_pub(const br_ec_impl *impl, br_ec_public_key *pk,
|
||||
void *kbuf, const br_ec_private_key *sk);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1346
enclave/include/bearssl/bearssl_hash.h
Normal file
1346
enclave/include/bearssl/bearssl_hash.h
Normal file
File diff suppressed because it is too large
Load Diff
241
enclave/include/bearssl/bearssl_hmac.h
Normal file
241
enclave/include/bearssl/bearssl_hmac.h
Normal file
@ -0,0 +1,241 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef BR_BEARSSL_HMAC_H__
|
||||
#define BR_BEARSSL_HMAC_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "bearssl_hash.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \file bearssl_hmac.h
|
||||
*
|
||||
* # HMAC
|
||||
*
|
||||
* HMAC is initialized with a key and an underlying hash function; it
|
||||
* then fills a "key context". That context contains the processed
|
||||
* key.
|
||||
*
|
||||
* With the key context, a HMAC context can be initialized to process
|
||||
* the input bytes and obtain the MAC output. The key context is not
|
||||
* modified during that process, and can be reused.
|
||||
*
|
||||
* IMPORTANT: HMAC shall be used only with functions that have the
|
||||
* following properties:
|
||||
*
|
||||
* - hash output size does not exceed 64 bytes;
|
||||
* - hash internal state size does not exceed 64 bytes;
|
||||
* - internal block length is a power of 2 between 16 and 256 bytes.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief HMAC key context.
|
||||
*
|
||||
* The HMAC key context is initialised with a hash function implementation
|
||||
* and a secret key. Contents are opaque (callers should not access them
|
||||
* directly). The caller is responsible for allocating the context where
|
||||
* appropriate. Context initialisation and usage incurs no dynamic
|
||||
* allocation, so there is no release function.
|
||||
*/
|
||||
typedef struct {
|
||||
#ifndef BR_DOXYGEN_IGNORE
|
||||
const br_hash_class *dig_vtable;
|
||||
unsigned char ksi[64], kso[64];
|
||||
#endif
|
||||
} br_hmac_key_context;
|
||||
|
||||
/**
|
||||
* \brief HMAC key context initialisation.
|
||||
*
|
||||
* Initialise the key context with the provided key, using the hash function
|
||||
* identified by `digest_vtable`. This supports arbitrary key lengths.
|
||||
*
|
||||
* \param kc HMAC key context to initialise.
|
||||
* \param digest_vtable pointer to the hash function implementation vtable.
|
||||
* \param key pointer to the HMAC secret key.
|
||||
* \param key_len HMAC secret key length (in bytes).
|
||||
*/
|
||||
void br_hmac_key_init(br_hmac_key_context *kc,
|
||||
const br_hash_class *digest_vtable, const void *key, size_t key_len);
|
||||
|
||||
/*
|
||||
* \brief Get the underlying hash function.
|
||||
*
|
||||
* This function returns a pointer to the implementation vtable of the
|
||||
* hash function used for this HMAC key context.
|
||||
*
|
||||
* \param kc HMAC key context.
|
||||
* \return the hash function implementation.
|
||||
*/
|
||||
static inline const br_hash_class *br_hmac_key_get_digest(
|
||||
const br_hmac_key_context *kc)
|
||||
{
|
||||
return kc->dig_vtable;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief HMAC computation context.
|
||||
*
|
||||
* The HMAC computation context maintains the state for a single HMAC
|
||||
* computation. It is modified as input bytes are injected. The context
|
||||
* is caller-allocated and has no release function since it does not
|
||||
* dynamically allocate external resources. Its contents are opaque.
|
||||
*/
|
||||
typedef struct {
|
||||
#ifndef BR_DOXYGEN_IGNORE
|
||||
br_hash_compat_context dig;
|
||||
unsigned char kso[64];
|
||||
size_t out_len;
|
||||
#endif
|
||||
} br_hmac_context;
|
||||
|
||||
/**
|
||||
* \brief HMAC computation initialisation.
|
||||
*
|
||||
* Initialise a HMAC context with a key context. The key context is
|
||||
* unmodified. Relevant data from the key context is immediately copied;
|
||||
* the key context can thus be independently reused, modified or released
|
||||
* without impacting this HMAC computation.
|
||||
*
|
||||
* An explicit output length can be specified; the actual output length
|
||||
* will be the minimum of that value and the natural HMAC output length.
|
||||
* If `out_len` is 0, then the natural HMAC output length is selected. The
|
||||
* "natural output length" is the output length of the underlying hash
|
||||
* function.
|
||||
*
|
||||
* \param ctx HMAC context to initialise.
|
||||
* \param kc HMAC key context (already initialised with the key).
|
||||
* \param out_len HMAC output length (0 to select "natural length").
|
||||
*/
|
||||
void br_hmac_init(br_hmac_context *ctx,
|
||||
const br_hmac_key_context *kc, size_t out_len);
|
||||
|
||||
/**
|
||||
* \brief Get the HMAC output size.
|
||||
*
|
||||
* The HMAC output size is the number of bytes that will actually be
|
||||
* produced with `br_hmac_out()` with the provided context. This function
|
||||
* MUST NOT be called on a non-initialised HMAC computation context.
|
||||
* The returned value is the minimum of the HMAC natural length (output
|
||||
* size of the underlying hash function) and the `out_len` parameter which
|
||||
* was used with the last `br_hmac_init()` call on that context (if the
|
||||
* initialisation `out_len` parameter was 0, then this function will
|
||||
* return the HMAC natural length).
|
||||
*
|
||||
* \param ctx the (already initialised) HMAC computation context.
|
||||
* \return the HMAC actual output size.
|
||||
*/
|
||||
static inline size_t
|
||||
br_hmac_size(br_hmac_context *ctx)
|
||||
{
|
||||
return ctx->out_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* \brief Get the underlying hash function.
|
||||
*
|
||||
* This function returns a pointer to the implementation vtable of the
|
||||
* hash function used for this HMAC context.
|
||||
*
|
||||
* \param hc HMAC context.
|
||||
* \return the hash function implementation.
|
||||
*/
|
||||
static inline const br_hash_class *br_hmac_get_digest(
|
||||
const br_hmac_context *hc)
|
||||
{
|
||||
return hc->dig.vtable;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Inject some bytes in HMAC.
|
||||
*
|
||||
* The provided `len` bytes are injected as extra input in the HMAC
|
||||
* computation incarnated by the `ctx` HMAC context. It is acceptable
|
||||
* that `len` is zero, in which case `data` is ignored (and may be
|
||||
* `NULL`) and this function does nothing.
|
||||
*/
|
||||
void br_hmac_update(br_hmac_context *ctx, const void *data, size_t len);
|
||||
|
||||
/**
|
||||
* \brief Compute the HMAC output.
|
||||
*
|
||||
* The destination buffer MUST be large enough to accommodate the result;
|
||||
* its length is at most the "natural length" of HMAC (i.e. the output
|
||||
* length of the underlying hash function). The context is NOT modified;
|
||||
* further bytes may be processed. Thus, "partial HMAC" values can be
|
||||
* efficiently obtained.
|
||||
*
|
||||
* Returned value is the output length (in bytes).
|
||||
*
|
||||
* \param ctx HMAC computation context.
|
||||
* \param out destination buffer for the HMAC output.
|
||||
* \return the produced value length (in bytes).
|
||||
*/
|
||||
size_t br_hmac_out(const br_hmac_context *ctx, void *out);
|
||||
|
||||
/**
|
||||
* \brief Constant-time HMAC computation.
|
||||
*
|
||||
* This function compute the HMAC output in constant time. Some extra
|
||||
* input bytes are processed, then the output is computed. The extra
|
||||
* input consists in the `len` bytes pointed to by `data`. The `len`
|
||||
* parameter must lie between `min_len` and `max_len` (inclusive);
|
||||
* `max_len` bytes are actually read from `data`. Computing time (and
|
||||
* memory access pattern) will not depend upon the data byte contents or
|
||||
* the value of `len`.
|
||||
*
|
||||
* The output is written in the `out` buffer, that MUST be large enough
|
||||
* to receive it.
|
||||
*
|
||||
* The difference `max_len - min_len` MUST be less than 2<sup>30</sup>
|
||||
* (i.e. about one gigabyte).
|
||||
*
|
||||
* This function computes the output properly only if the underlying
|
||||
* hash function uses MD padding (i.e. MD5, SHA-1, SHA-224, SHA-256,
|
||||
* SHA-384 or SHA-512).
|
||||
*
|
||||
* The provided context is NOT modified.
|
||||
*
|
||||
* \param ctx the (already initialised) HMAC computation context.
|
||||
* \param data the extra input bytes.
|
||||
* \param len the extra input length (in bytes).
|
||||
* \param min_len minimum extra input length (in bytes).
|
||||
* \param max_len maximum extra input length (in bytes).
|
||||
* \param out destination buffer for the HMAC output.
|
||||
* \return the produced value length (in bytes).
|
||||
*/
|
||||
size_t br_hmac_outCT(const br_hmac_context *ctx,
|
||||
const void *data, size_t len, size_t min_len, size_t max_len,
|
||||
void *out);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
284
enclave/include/bearssl/bearssl_kdf.h
Normal file
284
enclave/include/bearssl/bearssl_kdf.h
Normal file
@ -0,0 +1,284 @@
|
||||
/*
|
||||
* Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef BR_BEARSSL_KDF_H__
|
||||
#define BR_BEARSSL_KDF_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "bearssl_hash.h"
|
||||
#include "bearssl_hmac.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \file bearssl_kdf.h
|
||||
*
|
||||
* # Key Derivation Functions
|
||||
*
|
||||
* KDF are functions that takes a variable length input, and provide a
|
||||
* variable length output, meant to be used to derive subkeys from a
|
||||
* master key.
|
||||
*
|
||||
* ## HKDF
|
||||
*
|
||||
* HKDF is a KDF defined by [RFC 5869](https://tools.ietf.org/html/rfc5869).
|
||||
* It is based on HMAC, itself using an underlying hash function. Any
|
||||
* hash function can be used, as long as it is compatible with the rules
|
||||
* for the HMAC implementation (i.e. output size is 64 bytes or less, hash
|
||||
* internal state size is 64 bytes or less, and the internal block length is
|
||||
* a power of 2 between 16 and 256 bytes). HKDF has two phases:
|
||||
*
|
||||
* - HKDF-Extract: the input data in ingested, along with a "salt" value.
|
||||
*
|
||||
* - HKDF-Expand: the output is produced, from the result of processing
|
||||
* the input and salt, and using an extra non-secret parameter called
|
||||
* "info".
|
||||
*
|
||||
* The "salt" and "info" strings are non-secret and can be empty. Their role
|
||||
* is normally to bind the input and output, respectively, to conventional
|
||||
* identifiers that qualifu them within the used protocol or application.
|
||||
*
|
||||
* The implementation defined in this file uses the following functions:
|
||||
*
|
||||
* - `br_hkdf_init()`: initialize an HKDF context, with a hash function,
|
||||
* and the salt. This starts the HKDF-Extract process.
|
||||
*
|
||||
* - `br_hkdf_inject()`: inject more input bytes. This function may be
|
||||
* called repeatedly if the input data is provided by chunks.
|
||||
*
|
||||
* - `br_hkdf_flip()`: end the HKDF-Extract process, and start the
|
||||
* HKDF-Expand process.
|
||||
*
|
||||
* - `br_hkdf_produce()`: get the next bytes of output. This function
|
||||
* may be called several times to obtain the full output by chunks.
|
||||
* For correct HKDF processing, the same "info" string must be
|
||||
* provided for each call.
|
||||
*
|
||||
* Note that the HKDF total output size (the number of bytes that
|
||||
* HKDF-Expand is willing to produce) is limited: if the hash output size
|
||||
* is _n_ bytes, then the maximum output size is _255*n_.
|
||||
*
|
||||
* ## SHAKE
|
||||
*
|
||||
* SHAKE is defined in
|
||||
* [FIPS 202](https://csrc.nist.gov/publications/detail/fips/202/final)
|
||||
* under two versions: SHAKE128 and SHAKE256, offering an alleged
|
||||
* "security level" of 128 and 256 bits, respectively (SHAKE128 is
|
||||
* about 20 to 25% faster than SHAKE256). SHAKE internally relies on
|
||||
* the Keccak family of sponge functions, not on any externally provided
|
||||
* hash function. Contrary to HKDF, SHAKE does not have a concept of
|
||||
* either a "salt" or an "info" string. The API consists in four
|
||||
* functions:
|
||||
*
|
||||
* - `br_shake_init()`: initialize a SHAKE context for a given
|
||||
* security level.
|
||||
*
|
||||
* - `br_shake_inject()`: inject more input bytes. This function may be
|
||||
* called repeatedly if the input data is provided by chunks.
|
||||
*
|
||||
* - `br_shake_flip()`: end the data injection process, and start the
|
||||
* data production process.
|
||||
*
|
||||
* - `br_shake_produce()`: get the next bytes of output. This function
|
||||
* may be called several times to obtain the full output by chunks.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief HKDF context.
|
||||
*
|
||||
* The HKDF context is initialized with a hash function implementation
|
||||
* and a salt value. Contents are opaque (callers should not access them
|
||||
* directly). The caller is responsible for allocating the context where
|
||||
* appropriate. Context initialisation and usage incurs no dynamic
|
||||
* allocation, so there is no release function.
|
||||
*/
|
||||
typedef struct {
|
||||
#ifndef BR_DOXYGEN_IGNORE
|
||||
union {
|
||||
br_hmac_context hmac_ctx;
|
||||
br_hmac_key_context prk_ctx;
|
||||
} u;
|
||||
unsigned char buf[64];
|
||||
size_t ptr;
|
||||
size_t dig_len;
|
||||
unsigned chunk_num;
|
||||
#endif
|
||||
} br_hkdf_context;
|
||||
|
||||
/**
|
||||
* \brief HKDF context initialization.
|
||||
*
|
||||
* The underlying hash function and salt value are provided. Arbitrary
|
||||
* salt lengths can be used.
|
||||
*
|
||||
* HKDF makes a difference between a salt of length zero, and an
|
||||
* absent salt (the latter being equivalent to a salt consisting of
|
||||
* bytes of value zero, of the same length as the hash function output).
|
||||
* If `salt_len` is zero, then this function assumes that the salt is
|
||||
* present but of length zero. To specify an _absent_ salt, use
|
||||
* `BR_HKDF_NO_SALT` as `salt` parameter (`salt_len` is then ignored).
|
||||
*
|
||||
* \param hc HKDF context to initialise.
|
||||
* \param digest_vtable pointer to the hash function implementation vtable.
|
||||
* \param salt HKDF-Extract salt.
|
||||
* \param salt_len HKDF-Extract salt length (in bytes).
|
||||
*/
|
||||
void br_hkdf_init(br_hkdf_context *hc, const br_hash_class *digest_vtable,
|
||||
const void *salt, size_t salt_len);
|
||||
|
||||
/**
|
||||
* \brief The special "absent salt" value for HKDF.
|
||||
*/
|
||||
#define BR_HKDF_NO_SALT (&br_hkdf_no_salt)
|
||||
|
||||
#ifndef BR_DOXYGEN_IGNORE
|
||||
extern const unsigned char br_hkdf_no_salt;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief HKDF input injection (HKDF-Extract).
|
||||
*
|
||||
* This function injects some more input bytes ("key material") into
|
||||
* HKDF. This function may be called several times, after `br_hkdf_init()`
|
||||
* but before `br_hkdf_flip()`.
|
||||
*
|
||||
* \param hc HKDF context.
|
||||
* \param ikm extra input bytes.
|
||||
* \param ikm_len number of extra input bytes.
|
||||
*/
|
||||
void br_hkdf_inject(br_hkdf_context *hc, const void *ikm, size_t ikm_len);
|
||||
|
||||
/**
|
||||
* \brief HKDF switch to the HKDF-Expand phase.
|
||||
*
|
||||
* This call terminates the HKDF-Extract process (input injection), and
|
||||
* starts the HKDF-Expand process (output production).
|
||||
*
|
||||
* \param hc HKDF context.
|
||||
*/
|
||||
void br_hkdf_flip(br_hkdf_context *hc);
|
||||
|
||||
/**
|
||||
* \brief HKDF output production (HKDF-Expand).
|
||||
*
|
||||
* Produce more output bytes from the current state. This function may be
|
||||
* called several times, but only after `br_hkdf_flip()`.
|
||||
*
|
||||
* Returned value is the number of actually produced bytes. The total
|
||||
* output length is limited to 255 times the output length of the
|
||||
* underlying hash function.
|
||||
*
|
||||
* \param hc HKDF context.
|
||||
* \param info application specific information string.
|
||||
* \param info_len application specific information string length (in bytes).
|
||||
* \param out destination buffer for the HKDF output.
|
||||
* \param out_len the length of the requested output (in bytes).
|
||||
* \return the produced output length (in bytes).
|
||||
*/
|
||||
size_t br_hkdf_produce(br_hkdf_context *hc,
|
||||
const void *info, size_t info_len, void *out, size_t out_len);
|
||||
|
||||
/**
|
||||
* \brief SHAKE context.
|
||||
*
|
||||
* The HKDF context is initialized with a "security level". The internal
|
||||
* notion is called "capacity"; the capacity is twice the security level
|
||||
* (for instance, SHAKE128 has capacity 256).
|
||||
*
|
||||
* The caller is responsible for allocating the context where
|
||||
* appropriate. Context initialisation and usage incurs no dynamic
|
||||
* allocation, so there is no release function.
|
||||
*/
|
||||
typedef struct {
|
||||
#ifndef BR_DOXYGEN_IGNORE
|
||||
unsigned char dbuf[200];
|
||||
size_t dptr;
|
||||
size_t rate;
|
||||
uint64_t A[25];
|
||||
#endif
|
||||
} br_shake_context;
|
||||
|
||||
/**
|
||||
* \brief SHAKE context initialization.
|
||||
*
|
||||
* The context is initialized for the provided "security level".
|
||||
* Internally, this sets the "capacity" to twice the security level;
|
||||
* thus, for SHAKE128, the `security_level` parameter should be 128,
|
||||
* which corresponds to a 256-bit capacity.
|
||||
*
|
||||
* Allowed security levels are all multiples of 32, from 32 to 768,
|
||||
* inclusive. Larger security levels imply lower performance; levels
|
||||
* beyond 256 bits don't make much sense. Standard levels are 128
|
||||
* and 256 bits (for SHAKE128 and SHAKE256, respectively).
|
||||
*
|
||||
* \param sc SHAKE context to initialise.
|
||||
* \param security_level security level (in bits).
|
||||
*/
|
||||
void br_shake_init(br_shake_context *sc, int security_level);
|
||||
|
||||
/**
|
||||
* \brief SHAKE input injection.
|
||||
*
|
||||
* This function injects some more input bytes ("key material") into
|
||||
* SHAKE. This function may be called several times, after `br_shake_init()`
|
||||
* but before `br_shake_flip()`.
|
||||
*
|
||||
* \param sc SHAKE context.
|
||||
* \param data extra input bytes.
|
||||
* \param len number of extra input bytes.
|
||||
*/
|
||||
void br_shake_inject(br_shake_context *sc, const void *data, size_t len);
|
||||
|
||||
/**
|
||||
* \brief SHAKE switch to production phase.
|
||||
*
|
||||
* This call terminates the input injection process, and starts the
|
||||
* output production process.
|
||||
*
|
||||
* \param sc SHAKE context.
|
||||
*/
|
||||
void br_shake_flip(br_shake_context *hc);
|
||||
|
||||
/**
|
||||
* \brief SHAKE output production.
|
||||
*
|
||||
* Produce more output bytes from the current state. This function may be
|
||||
* called several times, but only after `br_shake_flip()`.
|
||||
*
|
||||
* There is no practical limit to the number of bytes that may be produced.
|
||||
*
|
||||
* \param sc SHAKE context.
|
||||
* \param out destination buffer for the SHAKE output.
|
||||
* \param len the length of the requested output (in bytes).
|
||||
*/
|
||||
void br_shake_produce(br_shake_context *sc, void *out, size_t len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
294
enclave/include/bearssl/bearssl_pem.h
Normal file
294
enclave/include/bearssl/bearssl_pem.h
Normal file
@ -0,0 +1,294 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef BR_BEARSSL_PEM_H__
|
||||
#define BR_BEARSSL_PEM_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \file bearssl_pem.h
|
||||
*
|
||||
* # PEM Support
|
||||
*
|
||||
* PEM is a traditional encoding layer use to store binary objects (in
|
||||
* particular X.509 certificates, and private keys) in text files. While
|
||||
* the acronym comes from an old, defunct standard ("Privacy Enhanced
|
||||
* Mail"), the format has been reused, with some variations, by many
|
||||
* systems, and is a _de facto_ standard, even though it is not, actually,
|
||||
* specified in all clarity anywhere.
|
||||
*
|
||||
* ## Format Details
|
||||
*
|
||||
* BearSSL contains a generic, streamed PEM decoder, which handles the
|
||||
* following format:
|
||||
*
|
||||
* - The input source (a sequence of bytes) is assumed to be the
|
||||
* encoding of a text file in an ASCII-compatible charset. This
|
||||
* includes ISO-8859-1, Windows-1252, and UTF-8 encodings. Each
|
||||
* line ends on a newline character (U+000A LINE FEED). The
|
||||
* U+000D CARRIAGE RETURN characters are ignored, so the code
|
||||
* accepts both Windows-style and Unix-style line endings.
|
||||
*
|
||||
* - Each object begins with a banner that occurs at the start of
|
||||
* a line; the first banner characters are "`-----BEGIN `" (five
|
||||
* dashes, the word "BEGIN", and a space). The banner matching is
|
||||
* not case-sensitive.
|
||||
*
|
||||
* - The _object name_ consists in the characters that follow the
|
||||
* banner start sequence, up to the end of the line, but without
|
||||
* trailing dashes (in "normal" PEM, there are five trailing
|
||||
* dashes, but this implementation is not picky about these dashes).
|
||||
* The BearSSL decoder normalises the name characters to uppercase
|
||||
* (for ASCII letters only) and accepts names up to 127 characters.
|
||||
*
|
||||
* - The object ends with a banner that again occurs at the start of
|
||||
* a line, and starts with "`-----END `" (again case-insensitive).
|
||||
*
|
||||
* - Between that start and end banner, only Base64 data shall occur.
|
||||
* Base64 converts each sequence of three bytes into four
|
||||
* characters; the four characters are ASCII letters, digits, "`+`"
|
||||
* or "`-`" signs, and one or two "`=`" signs may occur in the last
|
||||
* quartet. Whitespace is ignored (whitespace is any ASCII character
|
||||
* of code 32 or less, so control characters are whitespace) and
|
||||
* lines may have arbitrary length; the only restriction is that the
|
||||
* four characters of a quartet must appear on the same line (no
|
||||
* line break inside a quartet).
|
||||
*
|
||||
* - A single file may contain more than one PEM object. Bytes that
|
||||
* occur between objects are ignored.
|
||||
*
|
||||
*
|
||||
* ## PEM Decoder API
|
||||
*
|
||||
* The PEM decoder offers a state-machine API. The caller allocates a
|
||||
* decoder context, then injects source bytes. Source bytes are pushed
|
||||
* with `br_pem_decoder_push()`. The decoder stops accepting bytes when
|
||||
* it reaches an "event", which is either the start of an object, the
|
||||
* end of an object, or a decoding error within an object.
|
||||
*
|
||||
* The `br_pem_decoder_event()` function is used to obtain the current
|
||||
* event; it also clears it, thus allowing the decoder to accept more
|
||||
* bytes. When a object start event is raised, the decoder context
|
||||
* offers the found object name (normalised to ASCII uppercase).
|
||||
*
|
||||
* When an object is reached, the caller must set an appropriate callback
|
||||
* function, which will receive (by chunks) the decoded object data.
|
||||
*
|
||||
* Since the decoder context makes no dynamic allocation, it requires
|
||||
* no explicit deallocation.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief PEM decoder context.
|
||||
*
|
||||
* Contents are opaque (they should not be accessed directly).
|
||||
*/
|
||||
typedef struct {
|
||||
#ifndef BR_DOXYGEN_IGNORE
|
||||
/* CPU for the T0 virtual machine. */
|
||||
struct {
|
||||
uint32_t *dp;
|
||||
uint32_t *rp;
|
||||
const unsigned char *ip;
|
||||
} cpu;
|
||||
uint32_t dp_stack[32];
|
||||
uint32_t rp_stack[32];
|
||||
int err;
|
||||
|
||||
const unsigned char *hbuf;
|
||||
size_t hlen;
|
||||
|
||||
void (*dest)(void *dest_ctx, const void *src, size_t len);
|
||||
void *dest_ctx;
|
||||
|
||||
unsigned char event;
|
||||
char name[128];
|
||||
unsigned char buf[255];
|
||||
size_t ptr;
|
||||
#endif
|
||||
} br_pem_decoder_context;
|
||||
|
||||
/**
|
||||
* \brief Initialise a PEM decoder structure.
|
||||
*
|
||||
* \param ctx decoder context to initialise.
|
||||
*/
|
||||
void br_pem_decoder_init(br_pem_decoder_context *ctx);
|
||||
|
||||
/**
|
||||
* \brief Push some bytes into the decoder.
|
||||
*
|
||||
* Returned value is the number of bytes actually consumed; this may be
|
||||
* less than the number of provided bytes if an event is raised. When an
|
||||
* event is raised, it must be read (with `br_pem_decoder_event()`);
|
||||
* until the event is read, this function will return 0.
|
||||
*
|
||||
* \param ctx decoder context.
|
||||
* \param data new data bytes.
|
||||
* \param len number of new data bytes.
|
||||
* \return the number of bytes actually received (may be less than `len`).
|
||||
*/
|
||||
size_t br_pem_decoder_push(br_pem_decoder_context *ctx,
|
||||
const void *data, size_t len);
|
||||
|
||||
/**
|
||||
* \brief Set the receiver for decoded data.
|
||||
*
|
||||
* When an object is entered, the provided function (with opaque context
|
||||
* pointer) will be called repeatedly with successive chunks of decoded
|
||||
* data for that object. If `dest` is set to 0, then decoded data is
|
||||
* simply ignored. The receiver can be set at any time, but, in practice,
|
||||
* it should be called immediately after receiving a "start of object"
|
||||
* event.
|
||||
*
|
||||
* \param ctx decoder context.
|
||||
* \param dest callback for receiving decoded data.
|
||||
* \param dest_ctx opaque context pointer for the `dest` callback.
|
||||
*/
|
||||
static inline void
|
||||
br_pem_decoder_setdest(br_pem_decoder_context *ctx,
|
||||
void (*dest)(void *dest_ctx, const void *src, size_t len),
|
||||
void *dest_ctx)
|
||||
{
|
||||
ctx->dest = dest;
|
||||
ctx->dest_ctx = dest_ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the last event.
|
||||
*
|
||||
* If an event was raised, then this function returns the event value, and
|
||||
* also clears it, thereby allowing the decoder to proceed. If no event
|
||||
* was raised since the last call to `br_pem_decoder_event()`, then this
|
||||
* function returns 0.
|
||||
*
|
||||
* \param ctx decoder context.
|
||||
* \return the raised event, or 0.
|
||||
*/
|
||||
int br_pem_decoder_event(br_pem_decoder_context *ctx);
|
||||
|
||||
/**
|
||||
* \brief Event: start of object.
|
||||
*
|
||||
* This event is raised when the start of a new object has been detected.
|
||||
* The object name (normalised to uppercase) can be accessed with
|
||||
* `br_pem_decoder_name()`.
|
||||
*/
|
||||
#define BR_PEM_BEGIN_OBJ 1
|
||||
|
||||
/**
|
||||
* \brief Event: end of object.
|
||||
*
|
||||
* This event is raised when the end of the current object is reached
|
||||
* (normally, i.e. with no decoding error).
|
||||
*/
|
||||
#define BR_PEM_END_OBJ 2
|
||||
|
||||
/**
|
||||
* \brief Event: decoding error.
|
||||
*
|
||||
* This event is raised when decoding fails within an object.
|
||||
* This formally closes the current object and brings the decoder back
|
||||
* to the "out of any object" state. The offending line in the source
|
||||
* is consumed.
|
||||
*/
|
||||
#define BR_PEM_ERROR 3
|
||||
|
||||
/**
|
||||
* \brief Get the name of the encountered object.
|
||||
*
|
||||
* The encountered object name is defined only when the "start of object"
|
||||
* event is raised. That name is normalised to uppercase (for ASCII letters
|
||||
* only) and does not include trailing dashes.
|
||||
*
|
||||
* \param ctx decoder context.
|
||||
* \return the current object name.
|
||||
*/
|
||||
static inline const char *
|
||||
br_pem_decoder_name(br_pem_decoder_context *ctx)
|
||||
{
|
||||
return ctx->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Encode an object in PEM.
|
||||
*
|
||||
* This function encodes the provided binary object (`data`, of length `len`
|
||||
* bytes) into PEM. The `banner` text will be included in the header and
|
||||
* footer (e.g. use `"CERTIFICATE"` to get a `"BEGIN CERTIFICATE"` header).
|
||||
*
|
||||
* The length (in characters) of the PEM output is returned; that length
|
||||
* does NOT include the terminating zero, that this function nevertheless
|
||||
* adds. If using the returned value for allocation purposes, the allocated
|
||||
* buffer size MUST be at least one byte larger than the returned size.
|
||||
*
|
||||
* If `dest` is `NULL`, then the encoding does not happen; however, the
|
||||
* length of the encoded object is still computed and returned.
|
||||
*
|
||||
* The `data` pointer may be `NULL` only if `len` is zero (when encoding
|
||||
* an object of length zero, which is not very useful), or when `dest`
|
||||
* is `NULL` (in that case, source data bytes are ignored).
|
||||
*
|
||||
* Some `flags` can be specified to alter the encoding behaviour:
|
||||
*
|
||||
* - If `BR_PEM_LINE64` is set, then line-breaking will occur after
|
||||
* every 64 characters of output, instead of the default of 76.
|
||||
*
|
||||
* - If `BR_PEM_CRLF` is set, then end-of-line sequence will use
|
||||
* CR+LF instead of a single LF.
|
||||
*
|
||||
* The `data` and `dest` buffers may overlap, in which case the source
|
||||
* binary data is destroyed in the process. Note that the PEM-encoded output
|
||||
* is always larger than the source binary.
|
||||
*
|
||||
* \param dest the destination buffer (or `NULL`).
|
||||
* \param data the source buffer (can be `NULL` in some cases).
|
||||
* \param len the source length (in bytes).
|
||||
* \param banner the PEM banner expression.
|
||||
* \param flags the behavioural flags.
|
||||
* \return the PEM object length (in characters), EXCLUDING the final zero.
|
||||
*/
|
||||
size_t br_pem_encode(void *dest, const void *data, size_t len,
|
||||
const char *banner, unsigned flags);
|
||||
|
||||
/**
|
||||
* \brief PEM encoding flag: split lines at 64 characters.
|
||||
*/
|
||||
#define BR_PEM_LINE64 0x0001
|
||||
|
||||
/**
|
||||
* \brief PEM encoding flag: use CR+LF line endings.
|
||||
*/
|
||||
#define BR_PEM_CRLF 0x0002
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
150
enclave/include/bearssl/bearssl_prf.h
Normal file
150
enclave/include/bearssl/bearssl_prf.h
Normal file
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef BR_BEARSSL_PRF_H__
|
||||
#define BR_BEARSSL_PRF_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \file bearssl_prf.h
|
||||
*
|
||||
* # The TLS PRF
|
||||
*
|
||||
* The "PRF" is the pseudorandom function used internally during the
|
||||
* SSL/TLS handshake, notably to expand negotiated shared secrets into
|
||||
* the symmetric encryption keys that will be used to process the
|
||||
* application data.
|
||||
*
|
||||
* TLS 1.0 and 1.1 define a PRF that is based on both MD5 and SHA-1. This
|
||||
* is implemented by the `br_tls10_prf()` function.
|
||||
*
|
||||
* TLS 1.2 redefines the PRF, using an explicit hash function. The
|
||||
* `br_tls12_sha256_prf()` and `br_tls12_sha384_prf()` functions apply that
|
||||
* PRF with, respectively, SHA-256 and SHA-384. Most standard cipher suites
|
||||
* rely on the SHA-256 based PRF, but some use SHA-384.
|
||||
*
|
||||
* The PRF always uses as input three parameters: a "secret" (some
|
||||
* bytes), a "label" (ASCII string), and a "seed" (again some bytes). An
|
||||
* arbitrary output length can be produced. The "seed" is provided as an
|
||||
* arbitrary number of binary chunks, that gets internally concatenated.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Type for a seed chunk.
|
||||
*
|
||||
* Each chunk may have an arbitrary length, and may be empty (no byte at
|
||||
* all). If the chunk length is zero, then the pointer to the chunk data
|
||||
* may be `NULL`.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* \brief Pointer to the chunk data.
|
||||
*/
|
||||
const void *data;
|
||||
|
||||
/**
|
||||
* \brief Chunk length (in bytes).
|
||||
*/
|
||||
size_t len;
|
||||
} br_tls_prf_seed_chunk;
|
||||
|
||||
/**
|
||||
* \brief PRF implementation for TLS 1.0 and 1.1.
|
||||
*
|
||||
* This PRF is the one specified by TLS 1.0 and 1.1. It internally uses
|
||||
* MD5 and SHA-1.
|
||||
*
|
||||
* \param dst destination buffer.
|
||||
* \param len output length (in bytes).
|
||||
* \param secret secret value (key) for this computation.
|
||||
* \param secret_len length of "secret" (in bytes).
|
||||
* \param label PRF label (zero-terminated ASCII string).
|
||||
* \param seed_num number of seed chunks.
|
||||
* \param seed seed chnks for this computation (usually non-secret).
|
||||
*/
|
||||
void br_tls10_prf(void *dst, size_t len,
|
||||
const void *secret, size_t secret_len, const char *label,
|
||||
size_t seed_num, const br_tls_prf_seed_chunk *seed);
|
||||
|
||||
/**
|
||||
* \brief PRF implementation for TLS 1.2, with SHA-256.
|
||||
*
|
||||
* This PRF is the one specified by TLS 1.2, when the underlying hash
|
||||
* function is SHA-256.
|
||||
*
|
||||
* \param dst destination buffer.
|
||||
* \param len output length (in bytes).
|
||||
* \param secret secret value (key) for this computation.
|
||||
* \param secret_len length of "secret" (in bytes).
|
||||
* \param label PRF label (zero-terminated ASCII string).
|
||||
* \param seed_num number of seed chunks.
|
||||
* \param seed seed chnks for this computation (usually non-secret).
|
||||
*/
|
||||
void br_tls12_sha256_prf(void *dst, size_t len,
|
||||
const void *secret, size_t secret_len, const char *label,
|
||||
size_t seed_num, const br_tls_prf_seed_chunk *seed);
|
||||
|
||||
/**
|
||||
* \brief PRF implementation for TLS 1.2, with SHA-384.
|
||||
*
|
||||
* This PRF is the one specified by TLS 1.2, when the underlying hash
|
||||
* function is SHA-384.
|
||||
*
|
||||
* \param dst destination buffer.
|
||||
* \param len output length (in bytes).
|
||||
* \param secret secret value (key) for this computation.
|
||||
* \param secret_len length of "secret" (in bytes).
|
||||
* \param label PRF label (zero-terminated ASCII string).
|
||||
* \param seed_num number of seed chunks.
|
||||
* \param seed seed chnks for this computation (usually non-secret).
|
||||
*/
|
||||
void br_tls12_sha384_prf(void *dst, size_t len,
|
||||
const void *secret, size_t secret_len, const char *label,
|
||||
size_t seed_num, const br_tls_prf_seed_chunk *seed);
|
||||
|
||||
/**
|
||||
* brief A convenient type name for a PRF implementation.
|
||||
*
|
||||
* \param dst destination buffer.
|
||||
* \param len output length (in bytes).
|
||||
* \param secret secret value (key) for this computation.
|
||||
* \param secret_len length of "secret" (in bytes).
|
||||
* \param label PRF label (zero-terminated ASCII string).
|
||||
* \param seed_num number of seed chunks.
|
||||
* \param seed seed chnks for this computation (usually non-secret).
|
||||
*/
|
||||
typedef void (*br_tls_prf_impl)(void *dst, size_t len,
|
||||
const void *secret, size_t secret_len, const char *label,
|
||||
size_t seed_num, const br_tls_prf_seed_chunk *seed);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
397
enclave/include/bearssl/bearssl_rand.h
Normal file
397
enclave/include/bearssl/bearssl_rand.h
Normal file
@ -0,0 +1,397 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef BR_BEARSSL_RAND_H__
|
||||
#define BR_BEARSSL_RAND_H__
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "bearssl_block.h"
|
||||
#include "bearssl_hash.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** \file bearssl_rand.h
|
||||
*
|
||||
* # Pseudo-Random Generators
|
||||
*
|
||||
* A PRNG is a state-based engine that outputs pseudo-random bytes on
|
||||
* demand. It is initialized with an initial seed, and additional seed
|
||||
* bytes can be added afterwards. Bytes produced depend on the seeds and
|
||||
* also on the exact sequence of calls (including sizes requested for
|
||||
* each call).
|
||||
*
|
||||
*
|
||||
* ## Procedural and OOP API
|
||||
*
|
||||
* For the PRNG of name "`xxx`", two API are provided. The _procedural_
|
||||
* API defined a context structure `br_xxx_context` and three functions:
|
||||
*
|
||||
* - `br_xxx_init()`
|
||||
*
|
||||
* Initialise the context with an initial seed.
|
||||
*
|
||||
* - `br_xxx_generate()`
|
||||
*
|
||||
* Produce some pseudo-random bytes.
|
||||
*
|
||||
* - `br_xxx_update()`
|
||||
*
|
||||
* Inject some additional seed.
|
||||
*
|
||||
* The initialisation function sets the first context field (`vtable`)
|
||||
* to a pointer to the vtable that supports the OOP API. The OOP API
|
||||
* provides access to the same functions through function pointers,
|
||||
* named `init()`, `generate()` and `update()`.
|
||||
*
|
||||
* Note that the context initialisation method may accept additional
|
||||
* parameters, provided as a 'const void *' pointer at API level. These
|
||||
* additional parameters depend on the implemented PRNG.
|
||||
*
|
||||
*
|
||||
* ## HMAC_DRBG
|
||||
*
|
||||
* HMAC_DRBG is defined in [NIST SP 800-90A Revision
|
||||
* 1](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf).
|
||||
* It uses HMAC repeatedly, over some configurable underlying hash
|
||||
* function. In BearSSL, it is implemented under the "`hmac_drbg`" name.
|
||||
* The "extra parameters" pointer for context initialisation should be
|
||||
* set to a pointer to the vtable for the underlying hash function (e.g.
|
||||
* pointer to `br_sha256_vtable` to use HMAC_DRBG with SHA-256).
|
||||
*
|
||||
* According to the NIST standard, each request shall produce up to
|
||||
* 2<sup>19</sup> bits (i.e. 64 kB of data); moreover, the context shall
|
||||
* be reseeded at least once every 2<sup>48</sup> requests. This
|
||||
* implementation does not maintain the reseed counter (the threshold is
|
||||
* too high to be reached in practice) and does not object to producing
|
||||
* more than 64 kB in a single request; thus, the code cannot fail,
|
||||
* which corresponds to the fact that the API has no room for error
|
||||
* codes. However, this implies that requesting more than 64 kB in one
|
||||
* `generate()` request, or making more than 2<sup>48</sup> requests
|
||||
* without reseeding, is formally out of NIST specification. There is
|
||||
* no currently known security penalty for exceeding the NIST limits,
|
||||
* and, in any case, HMAC_DRBG usage in implementing SSL/TLS always
|
||||
* stays much below these thresholds.
|
||||
*
|
||||
*
|
||||
* ## AESCTR_DRBG
|
||||
*
|
||||
* AESCTR_DRBG is a custom PRNG based on AES-128 in CTR mode. This is
|
||||
* meant to be used only in situations where you are desperate for
|
||||
* speed, and have an hardware-optimized AES/CTR implementation. Whether
|
||||
* this will yield perceptible improvements depends on what you use the
|
||||
* pseudorandom bytes for, and how many you want; for instance, RSA key
|
||||
* pair generation uses a substantial amount of randomness, and using
|
||||
* AESCTR_DRBG instead of HMAC_DRBG yields a 15 to 20% increase in key
|
||||
* generation speed on a recent x86 CPU (Intel Core i7-6567U at 3.30 GHz).
|
||||
*
|
||||
* Internally, it uses CTR mode with successive counter values, starting
|
||||
* at zero (counter value expressed over 128 bits, big-endian convention).
|
||||
* The counter is not allowed to reach 32768; thus, every 32768*16 bytes
|
||||
* at most, the `update()` function is run (on an empty seed, if none is
|
||||
* provided). The `update()` function computes the new AES-128 key by
|
||||
* applying a custom hash function to the concatenation of a state-dependent
|
||||
* word (encryption of an all-one block with the current key) and the new
|
||||
* seed. The custom hash function uses Hirose's construction over AES-256;
|
||||
* see the comments in `aesctr_drbg.c` for details.
|
||||
*
|
||||
* This DRBG does not follow an existing standard, and thus should be
|
||||
* considered as inadequate for production use until it has been properly
|
||||
* analysed.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Class type for PRNG implementations.
|
||||
*
|
||||
* A `br_prng_class` instance references the methods implementing a PRNG.
|
||||
* Constant instances of this structure are defined for each implemented
|
||||
* PRNG. Such instances are also called "vtables".
|
||||
*/
|
||||
typedef struct br_prng_class_ br_prng_class;
|
||||
struct br_prng_class_ {
|
||||
/**
|
||||
* \brief Size (in bytes) of the context structure appropriate for
|
||||
* running this PRNG.
|
||||
*/
|
||||
size_t context_size;
|
||||
|
||||
/**
|
||||
* \brief Initialisation method.
|
||||
*
|
||||
* The context to initialise is provided as a pointer to its
|
||||
* first field (the vtable pointer); this function sets that
|
||||
* first field to a pointer to the vtable.
|
||||
*
|
||||
* The extra parameters depend on the implementation; each
|
||||
* implementation defines what kind of extra parameters it
|
||||
* expects (if any).
|
||||
*
|
||||
* Requirements on the initial seed depend on the implemented
|
||||
* PRNG.
|
||||
*
|
||||
* \param ctx PRNG context to initialise.
|
||||
* \param params extra parameters for the PRNG.
|
||||
* \param seed initial seed.
|
||||
* \param seed_len initial seed length (in bytes).
|
||||
*/
|
||||
void (*init)(const br_prng_class **ctx, const void *params,
|
||||
const void *seed, size_t seed_len);
|
||||
|
||||
/**
|
||||
* \brief Random bytes generation.
|
||||
*
|
||||
* This method produces `len` pseudorandom bytes, in the `out`
|
||||
* buffer. The context is updated accordingly.
|
||||
*
|
||||
* \param ctx PRNG context.
|
||||
* \param out output buffer.
|
||||
* \param len number of pseudorandom bytes to produce.
|
||||
*/
|
||||
void (*generate)(const br_prng_class **ctx, void *out, size_t len);
|
||||
|
||||
/**
|
||||
* \brief Inject additional seed bytes.
|
||||
*
|
||||
* The provided seed bytes are added into the PRNG internal
|
||||
* entropy pool.
|
||||
*
|
||||
* \param ctx PRNG context.
|
||||
* \param seed additional seed.
|
||||
* \param seed_len additional seed length (in bytes).
|
||||
*/
|
||||
void (*update)(const br_prng_class **ctx,
|
||||
const void *seed, size_t seed_len);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Context for HMAC_DRBG.
|
||||
*
|
||||
* The context contents are opaque, except the first field, which
|
||||
* supports OOP.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* \brief Pointer to the vtable.
|
||||
*
|
||||
* This field is set with the initialisation method/function.
|
||||
*/
|
||||
const br_prng_class *vtable;
|
||||
#ifndef BR_DOXYGEN_IGNORE
|
||||
unsigned char K[64];
|
||||
unsigned char V[64];
|
||||
const br_hash_class *digest_class;
|
||||
#endif
|
||||
} br_hmac_drbg_context;
|
||||
|
||||
/**
|
||||
* \brief Statically allocated, constant vtable for HMAC_DRBG.
|
||||
*/
|
||||
extern const br_prng_class br_hmac_drbg_vtable;
|
||||
|
||||
/**
|
||||
* \brief HMAC_DRBG initialisation.
|
||||
*
|
||||
* The context to initialise is provided as a pointer to its first field
|
||||
* (the vtable pointer); this function sets that first field to a
|
||||
* pointer to the vtable.
|
||||
*
|
||||
* The `seed` value is what is called, in NIST terminology, the
|
||||
* concatenation of the "seed", "nonce" and "personalization string", in
|
||||
* that order.
|
||||
*
|
||||
* The `digest_class` parameter defines the underlying hash function.
|
||||
* Formally, the NIST standard specifies that the hash function shall
|
||||
* be only SHA-1 or one of the SHA-2 functions. This implementation also
|
||||
* works with any other implemented hash function (such as MD5), but
|
||||
* this is non-standard and therefore not recommended.
|
||||
*
|
||||
* \param ctx HMAC_DRBG context to initialise.
|
||||
* \param digest_class vtable for the underlying hash function.
|
||||
* \param seed initial seed.
|
||||
* \param seed_len initial seed length (in bytes).
|
||||
*/
|
||||
void br_hmac_drbg_init(br_hmac_drbg_context *ctx,
|
||||
const br_hash_class *digest_class, const void *seed, size_t seed_len);
|
||||
|
||||
/**
|
||||
* \brief Random bytes generation with HMAC_DRBG.
|
||||
*
|
||||
* This method produces `len` pseudorandom bytes, in the `out`
|
||||
* buffer. The context is updated accordingly. Formally, requesting
|
||||
* more than 65536 bytes in one request falls out of specification
|
||||
* limits (but it won't fail).
|
||||
*
|
||||
* \param ctx HMAC_DRBG context.
|
||||
* \param out output buffer.
|
||||
* \param len number of pseudorandom bytes to produce.
|
||||
*/
|
||||
void br_hmac_drbg_generate(br_hmac_drbg_context *ctx, void *out, size_t len);
|
||||
|
||||
/**
|
||||
* \brief Inject additional seed bytes in HMAC_DRBG.
|
||||
*
|
||||
* The provided seed bytes are added into the HMAC_DRBG internal
|
||||
* entropy pool. The process does not _replace_ existing entropy,
|
||||
* thus pushing non-random bytes (i.e. bytes which are known to the
|
||||
* attackers) does not degrade the overall quality of generated bytes.
|
||||
*
|
||||
* \param ctx HMAC_DRBG context.
|
||||
* \param seed additional seed.
|
||||
* \param seed_len additional seed length (in bytes).
|
||||
*/
|
||||
void br_hmac_drbg_update(br_hmac_drbg_context *ctx,
|
||||
const void *seed, size_t seed_len);
|
||||
|
||||
/**
|
||||
* \brief Get the hash function implementation used by a given instance of
|
||||
* HMAC_DRBG.
|
||||
*
|
||||
* This calls MUST NOT be performed on a context which was not
|
||||
* previously initialised.
|
||||
*
|
||||
* \param ctx HMAC_DRBG context.
|
||||
* \return the hash function vtable.
|
||||
*/
|
||||
static inline const br_hash_class *
|
||||
br_hmac_drbg_get_hash(const br_hmac_drbg_context *ctx)
|
||||
{
|
||||
return ctx->digest_class;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Type for a provider of entropy seeds.
|
||||
*
|
||||
* A "seeder" is a function that is able to obtain random values from
|
||||
* some source and inject them as entropy seed in a PRNG. A seeder
|
||||
* shall guarantee that the total entropy of the injected seed is large
|
||||
* enough to seed a PRNG for purposes of cryptographic key generation
|
||||
* (i.e. at least 128 bits).
|
||||
*
|
||||
* A seeder may report a failure to obtain adequate entropy. Seeders
|
||||
* shall endeavour to fix themselves transient errors by trying again;
|
||||
* thus, callers may consider reported errors as permanent.
|
||||
*
|
||||
* \param ctx PRNG context to seed.
|
||||
* \return 1 on success, 0 on error.
|
||||
*/
|
||||
typedef int (*br_prng_seeder)(const br_prng_class **ctx);
|
||||
|
||||
/**
|
||||
* \brief Get a seeder backed by the operating system or hardware.
|
||||
*
|
||||
* Get a seeder that feeds on RNG facilities provided by the current
|
||||
* operating system or hardware. If no such facility is known, then 0
|
||||
* is returned.
|
||||
*
|
||||
* If `name` is not `NULL`, then `*name` is set to a symbolic string
|
||||
* that identifies the seeder implementation. If no seeder is returned
|
||||
* and `name` is not `NULL`, then `*name` is set to a pointer to the
|
||||
* constant string `"none"`.
|
||||
*
|
||||
* \param name receiver for seeder name, or `NULL`.
|
||||
* \return the system seeder, if available, or 0.
|
||||
*/
|
||||
br_prng_seeder br_prng_seeder_system(const char **name);
|
||||
|
||||
/**
|
||||
* \brief Context for AESCTR_DRBG.
|
||||
*
|
||||
* The context contents are opaque, except the first field, which
|
||||
* supports OOP.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* \brief Pointer to the vtable.
|
||||
*
|
||||
* This field is set with the initialisation method/function.
|
||||
*/
|
||||
const br_prng_class *vtable;
|
||||
#ifndef BR_DOXYGEN_IGNORE
|
||||
br_aes_gen_ctr_keys sk;
|
||||
uint32_t cc;
|
||||
#endif
|
||||
} br_aesctr_drbg_context;
|
||||
|
||||
/**
|
||||
* \brief Statically allocated, constant vtable for AESCTR_DRBG.
|
||||
*/
|
||||
extern const br_prng_class br_aesctr_drbg_vtable;
|
||||
|
||||
/**
|
||||
* \brief AESCTR_DRBG initialisation.
|
||||
*
|
||||
* The context to initialise is provided as a pointer to its first field
|
||||
* (the vtable pointer); this function sets that first field to a
|
||||
* pointer to the vtable.
|
||||
*
|
||||
* The internal AES key is first set to the all-zero key; then, the
|
||||
* `br_aesctr_drbg_update()` function is called with the provided `seed`.
|
||||
* The call is performed even if the seed length (`seed_len`) is zero.
|
||||
*
|
||||
* The `aesctr` parameter defines the underlying AES/CTR implementation.
|
||||
*
|
||||
* \param ctx AESCTR_DRBG context to initialise.
|
||||
* \param aesctr vtable for the AES/CTR implementation.
|
||||
* \param seed initial seed (can be `NULL` if `seed_len` is zero).
|
||||
* \param seed_len initial seed length (in bytes).
|
||||
*/
|
||||
void br_aesctr_drbg_init(br_aesctr_drbg_context *ctx,
|
||||
const br_block_ctr_class *aesctr, const void *seed, size_t seed_len);
|
||||
|
||||
/**
|
||||
* \brief Random bytes generation with AESCTR_DRBG.
|
||||
*
|
||||
* This method produces `len` pseudorandom bytes, in the `out`
|
||||
* buffer. The context is updated accordingly.
|
||||
*
|
||||
* \param ctx AESCTR_DRBG context.
|
||||
* \param out output buffer.
|
||||
* \param len number of pseudorandom bytes to produce.
|
||||
*/
|
||||
void br_aesctr_drbg_generate(br_aesctr_drbg_context *ctx,
|
||||
void *out, size_t len);
|
||||
|
||||
/**
|
||||
* \brief Inject additional seed bytes in AESCTR_DRBG.
|
||||
*
|
||||
* The provided seed bytes are added into the AESCTR_DRBG internal
|
||||
* entropy pool. The process does not _replace_ existing entropy,
|
||||
* thus pushing non-random bytes (i.e. bytes which are known to the
|
||||
* attackers) does not degrade the overall quality of generated bytes.
|
||||
*
|
||||
* \param ctx AESCTR_DRBG context.
|
||||
* \param seed additional seed.
|
||||
* \param seed_len additional seed length (in bytes).
|
||||
*/
|
||||
void br_aesctr_drbg_update(br_aesctr_drbg_context *ctx,
|
||||
const void *seed, size_t seed_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1655
enclave/include/bearssl/bearssl_rsa.h
Normal file
1655
enclave/include/bearssl/bearssl_rsa.h
Normal file
File diff suppressed because it is too large
Load Diff
4296
enclave/include/bearssl/bearssl_ssl.h
Normal file
4296
enclave/include/bearssl/bearssl_ssl.h
Normal file
File diff suppressed because it is too large
Load Diff
1397
enclave/include/bearssl/bearssl_x509.h
Normal file
1397
enclave/include/bearssl/bearssl_x509.h
Normal file
File diff suppressed because it is too large
Load Diff
487
enclave/include/cmockery.h
Normal file
487
enclave/include/cmockery.h
Normal file
@ -0,0 +1,487 @@
|
||||
/*
|
||||
* Copyright 2008 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef CMOCKERY_H_
|
||||
#define CMOCKERY_H_
|
||||
/*
|
||||
* These headers or their equivalents should be included prior to including
|
||||
* this header file.
|
||||
*
|
||||
* #include <stdarg.h>
|
||||
* #include <stddef.h>
|
||||
* #include <setjmp.h>
|
||||
*
|
||||
* This allows test applications to use custom definitions of C standard
|
||||
* library functions and types.
|
||||
*/
|
||||
|
||||
// For those who are used to __func__ from gcc.
|
||||
#ifndef __func__
|
||||
#define __func__ __FUNCTION__
|
||||
#endif
|
||||
|
||||
/* Largest integral type. This type should be large enough to hold any
|
||||
* pointer or integer supported by the compiler. */
|
||||
#ifndef LargestIntegralType
|
||||
#define LargestIntegralType uintmax_t
|
||||
#endif // LargestIntegralType
|
||||
|
||||
// Printf format used to display LargestIntegralType.
|
||||
#ifndef LargestIntegralTypePrintfFormat
|
||||
#ifdef _WIN32
|
||||
#define LargestIntegralTypePrintfFormat "%I64x"
|
||||
#else
|
||||
#define LargestIntegralTypePrintfFormat "%llx"
|
||||
#endif // _WIN32
|
||||
#endif // LargestIntegralTypePrintfFormat
|
||||
|
||||
// Perform an unsigned cast to LargestIntegralType.
|
||||
#define cast_to_largest_integral_type(value) \
|
||||
((LargestIntegralType)(value))
|
||||
|
||||
// Retrieves a return value for the current function.
|
||||
#define mock() _mock(__func__, __FILE__, __LINE__)
|
||||
|
||||
/* Stores a value to be returned by the specified function later.
|
||||
* The count parameter returns the number of times the value should be returned
|
||||
* by mock(). If count is set to -1 the value will always be returned.
|
||||
*/
|
||||
#define will_return(function, value) \
|
||||
_will_return(#function, __FILE__, __LINE__, \
|
||||
cast_to_largest_integral_type(value), 1)
|
||||
#define will_return_count(function, value, count) \
|
||||
_will_return(#function, __FILE__, __LINE__, \
|
||||
cast_to_largest_integral_type(value), count)
|
||||
|
||||
/* Add a custom parameter checking function. If the event parameter is NULL
|
||||
* the event structure is allocated internally by this function. If event
|
||||
* parameter is provided it must be allocated on the heap and doesn't need to
|
||||
* be deallocated by the caller.
|
||||
*/
|
||||
#define expect_check(function, parameter, check_function, check_data) \
|
||||
_expect_check(#function, #parameter, __FILE__, __LINE__, check_function, \
|
||||
cast_to_largest_integral_type(check_data), NULL, 0)
|
||||
|
||||
/* Add an event to check a parameter, using check_expected(), against a set of
|
||||
* values. See will_return() for a description of the count parameter.
|
||||
*/
|
||||
#define expect_in_set(function, parameter, value_array) \
|
||||
expect_in_set_count(function, parameter, value_array, 1)
|
||||
#define expect_in_set_count(function, parameter, value_array, count) \
|
||||
_expect_in_set(#function, #parameter, __FILE__, __LINE__, value_array, \
|
||||
sizeof(value_array) / sizeof((value_array)[0]), count)
|
||||
#define expect_not_in_set(function, parameter, value_array) \
|
||||
expect_not_in_set_count(function, parameter, value_array, 1)
|
||||
#define expect_not_in_set_count(function, parameter, value_array, count) \
|
||||
_expect_not_in_set( \
|
||||
#function, #parameter, __FILE__, __LINE__, value_array, \
|
||||
sizeof(value_array) / sizeof((value_array)[0]), count)
|
||||
|
||||
|
||||
/* Add an event to check a parameter, using check_expected(), against a
|
||||
* signed range. Where range is minimum <= value <= maximum.
|
||||
* See will_return() for a description of the count parameter.
|
||||
*/
|
||||
#define expect_in_range(function, parameter, minimum, maximum) \
|
||||
expect_in_range_count(function, parameter, minimum, maximum, 1)
|
||||
#define expect_in_range_count(function, parameter, minimum, maximum, count) \
|
||||
_expect_in_range(#function, #parameter, __FILE__, __LINE__, minimum, \
|
||||
maximum, count)
|
||||
|
||||
/* Add an event to check a parameter, using check_expected(), against a
|
||||
* signed range. Where range is value < minimum or value > maximum.
|
||||
* See will_return() for a description of the count parameter.
|
||||
*/
|
||||
#define expect_not_in_range(function, parameter, minimum, maximum) \
|
||||
expect_not_in_range_count(function, parameter, minimum, maximum, 1)
|
||||
#define expect_not_in_range_count(function, parameter, minimum, maximum, \
|
||||
count) \
|
||||
_expect_not_in_range(#function, #parameter, __FILE__, __LINE__, \
|
||||
minimum, maximum, count)
|
||||
|
||||
/* Add an event to check whether a parameter, using check_expected(), is or
|
||||
* isn't a value. See will_return() for a description of the count parameter.
|
||||
*/
|
||||
#define expect_value(function, parameter, value) \
|
||||
expect_value_count(function, parameter, value, 1)
|
||||
#define expect_value_count(function, parameter, value, count) \
|
||||
_expect_value(#function, #parameter, __FILE__, __LINE__, \
|
||||
cast_to_largest_integral_type(value), count)
|
||||
#define expect_not_value(function, parameter, value) \
|
||||
expect_not_value_count(function, parameter, value, 1)
|
||||
#define expect_not_value_count(function, parameter, value, count) \
|
||||
_expect_not_value(#function, #parameter, __FILE__, __LINE__, \
|
||||
cast_to_largest_integral_type(value), count)
|
||||
|
||||
/* Add an event to check whether a parameter, using check_expected(),
|
||||
* is or isn't a string. See will_return() for a description of the count
|
||||
* parameter.
|
||||
*/
|
||||
#define expect_string(function, parameter, string) \
|
||||
expect_string_count(function, parameter, string, 1)
|
||||
#define expect_string_count(function, parameter, string, count) \
|
||||
_expect_string(#function, #parameter, __FILE__, __LINE__, \
|
||||
(const char*)(string), count)
|
||||
#define expect_not_string(function, parameter, string) \
|
||||
expect_not_string_count(function, parameter, string, 1)
|
||||
#define expect_not_string_count(function, parameter, string, count) \
|
||||
_expect_not_string(#function, #parameter, __FILE__, __LINE__, \
|
||||
(const char*)(string), count)
|
||||
|
||||
/* Add an event to check whether a parameter, using check_expected() does or
|
||||
* doesn't match an area of memory. See will_return() for a description of
|
||||
* the count parameter.
|
||||
*/
|
||||
#define expect_memory(function, parameter, memory, size) \
|
||||
expect_memory_count(function, parameter, memory, size, 1)
|
||||
#define expect_memory_count(function, parameter, memory, size, count) \
|
||||
_expect_memory(#function, #parameter, __FILE__, __LINE__, \
|
||||
(const void*)(memory), size, count)
|
||||
#define expect_not_memory(function, parameter, memory, size) \
|
||||
expect_not_memory_count(function, parameter, memory, size, 1)
|
||||
#define expect_not_memory_count(function, parameter, memory, size, count) \
|
||||
_expect_not_memory(#function, #parameter, __FILE__, __LINE__, \
|
||||
(const void*)(memory), size, count)
|
||||
|
||||
|
||||
/* Add an event to allow any value for a parameter checked using
|
||||
* check_expected(). See will_return() for a description of the count
|
||||
* parameter.
|
||||
*/
|
||||
#define expect_any(function, parameter) \
|
||||
expect_any_count(function, parameter, 1)
|
||||
#define expect_any_count(function, parameter, count) \
|
||||
_expect_any(#function, #parameter, __FILE__, __LINE__, count)
|
||||
|
||||
/* Determine whether a function parameter is correct. This ensures the next
|
||||
* value queued by one of the expect_*() macros matches the specified variable.
|
||||
*/
|
||||
#define check_expected(parameter) \
|
||||
_check_expected(__func__, #parameter, __FILE__, __LINE__, \
|
||||
cast_to_largest_integral_type(parameter))
|
||||
|
||||
// Assert that the given expression is true.
|
||||
#define assert_true(c) _assert_true(cast_to_largest_integral_type(c), #c, \
|
||||
__FILE__, __LINE__)
|
||||
// Assert that the given expression is false.
|
||||
#define assert_false(c) _assert_true(!(cast_to_largest_integral_type(c)), #c, \
|
||||
__FILE__, __LINE__)
|
||||
|
||||
// Assert that the two given integers are equal, otherwise fail.
|
||||
#define assert_int_equal(a, b) \
|
||||
_assert_int_equal(cast_to_largest_integral_type(a), \
|
||||
cast_to_largest_integral_type(b), \
|
||||
__FILE__, __LINE__)
|
||||
// Assert that the two given integers are not equal, otherwise fail.
|
||||
#define assert_int_not_equal(a, b) \
|
||||
_assert_int_not_equal(cast_to_largest_integral_type(a), \
|
||||
cast_to_largest_integral_type(b), \
|
||||
__FILE__, __LINE__)
|
||||
|
||||
// Assert that the two given strings are equal, otherwise fail.
|
||||
#define assert_string_equal(a, b) \
|
||||
_assert_string_equal((const char*)(a), (const char*)(b), __FILE__, \
|
||||
__LINE__)
|
||||
// Assert that the two given strings are not equal, otherwise fail.
|
||||
#define assert_string_not_equal(a, b) \
|
||||
_assert_string_not_equal((const char*)(a), (const char*)(b), __FILE__, \
|
||||
__LINE__)
|
||||
|
||||
// Assert that the two given areas of memory are equal, otherwise fail.
|
||||
#define assert_memory_equal(a, b, size) \
|
||||
_assert_memory_equal((const char*)(a), (const char*)(b), size, __FILE__, \
|
||||
__LINE__)
|
||||
// Assert that the two given areas of memory are not equal, otherwise fail.
|
||||
#define assert_memory_not_equal(a, b, size) \
|
||||
_assert_memory_not_equal((const char*)(a), (const char*)(b), size, \
|
||||
__FILE__, __LINE__)
|
||||
|
||||
// Assert that the specified value is >= minimum and <= maximum.
|
||||
#define assert_in_range(value, minimum, maximum) \
|
||||
_assert_in_range( \
|
||||
cast_to_largest_integral_type(value), \
|
||||
cast_to_largest_integral_type(minimum), \
|
||||
cast_to_largest_integral_type(maximum), __FILE__, __LINE__)
|
||||
|
||||
// Assert that the specified value is < minumum or > maximum
|
||||
#define assert_not_in_range(value, minimum, maximum) \
|
||||
_assert_not_in_range( \
|
||||
cast_to_largest_integral_type(value), \
|
||||
cast_to_largest_integral_type(minimum), \
|
||||
cast_to_largest_integral_type(maximum), __FILE__, __LINE__)
|
||||
|
||||
// Assert that the specified value is within a set.
|
||||
#define assert_in_set(value, values, number_of_values) \
|
||||
_assert_in_set(value, values, number_of_values, __FILE__, __LINE__)
|
||||
// Assert that the specified value is not within a set.
|
||||
#define assert_not_in_set(value, values, number_of_values) \
|
||||
_assert_not_in_set(value, values, number_of_values, __FILE__, __LINE__)
|
||||
|
||||
|
||||
// Forces the test to fail immediately and quit.
|
||||
#define fail() _fail(__FILE__, __LINE__)
|
||||
|
||||
// Generic method to kick off testing
|
||||
#define run_test(f) _run_test(#f, f, NULL, UNIT_TEST_FUNCTION_TYPE_TEST, NULL)
|
||||
|
||||
// Initializes a UnitTest structure.
|
||||
#define unit_test(f) { #f, f, UNIT_TEST_FUNCTION_TYPE_TEST }
|
||||
#define unit_test_setup(test, setup) \
|
||||
{ #test "_" #setup, setup, UNIT_TEST_FUNCTION_TYPE_SETUP }
|
||||
#define unit_test_teardown(test, teardown) \
|
||||
{ #test "_" #teardown, teardown, UNIT_TEST_FUNCTION_TYPE_TEARDOWN }
|
||||
|
||||
/* Initialize an array of UnitTest structures with a setup function for a test
|
||||
* and a teardown function. Either setup or teardown can be NULL.
|
||||
*/
|
||||
#define unit_test_setup_teardown(test, setup, teardown) \
|
||||
unit_test_setup(test, setup), \
|
||||
unit_test(test), \
|
||||
unit_test_teardown(test, teardown)
|
||||
|
||||
/*
|
||||
* Run tests specified by an array of UnitTest structures. The following
|
||||
* example illustrates this macro's use with the unit_test macro.
|
||||
*
|
||||
* void Test0();
|
||||
* void Test1();
|
||||
*
|
||||
* int main(int argc, char* argv[]) {
|
||||
* const UnitTest tests[] = {
|
||||
* unit_test(Test0);
|
||||
* unit_test(Test1);
|
||||
* };
|
||||
* return run_tests(tests);
|
||||
* }
|
||||
*/
|
||||
#define run_tests(tests) _run_tests(tests, sizeof(tests) / sizeof(tests)[0])
|
||||
|
||||
// Dynamic allocators
|
||||
#define test_malloc(size) _test_malloc(size, __FILE__, __LINE__)
|
||||
#define test_memalign(alignment, size) _test_memalign(alignment, size, __FILE__, __LINE__)
|
||||
#define test_calloc(num, size) _test_calloc(num, size, __FILE__, __LINE__)
|
||||
#define test_free(ptr) _test_free(ptr, __FILE__, __LINE__)
|
||||
|
||||
// Redirect malloc, calloc and free to the unit test allocators.
|
||||
#if UNIT_TESTING
|
||||
#define malloc test_malloc
|
||||
#define memalign test_memalign
|
||||
#define calloc test_calloc
|
||||
#define free test_free
|
||||
#endif // UNIT_TESTING
|
||||
|
||||
/*
|
||||
* Ensure mock_assert() is called. If mock_assert() is called the assert
|
||||
* expression string is returned.
|
||||
* For example:
|
||||
*
|
||||
* #define assert mock_assert
|
||||
*
|
||||
* void showmessage(const char *message) {
|
||||
* assert(message);
|
||||
* }
|
||||
*
|
||||
* int main(int argc, const char* argv[]) {
|
||||
* expect_assert_failure(show_message(NULL));
|
||||
* printf("succeeded\n");
|
||||
* return 0;
|
||||
* }
|
||||
*/
|
||||
#define expect_assert_failure(function_call) \
|
||||
{ \
|
||||
const int expression = setjmp(global_expect_assert_env); \
|
||||
global_expecting_assert = 1; \
|
||||
if (expression) { \
|
||||
print_message("Expected assertion %s occurred\n", \
|
||||
*((const char**)&expression)); \
|
||||
global_expecting_assert = 0; \
|
||||
} else { \
|
||||
function_call ; \
|
||||
global_expecting_assert = 0; \
|
||||
print_error("Expected assert in %s\n", #function_call); \
|
||||
_fail(__FILE__, __LINE__); \
|
||||
} \
|
||||
}
|
||||
|
||||
// Function prototype for setup, test and teardown functions.
|
||||
typedef void (*UnitTestFunction)(void **state);
|
||||
|
||||
// Function that determines whether a function parameter value is correct.
|
||||
typedef int (*CheckParameterValue)(const LargestIntegralType value,
|
||||
const LargestIntegralType check_value_data);
|
||||
|
||||
// Type of the unit test function.
|
||||
typedef enum UnitTestFunctionType {
|
||||
UNIT_TEST_FUNCTION_TYPE_TEST = 0,
|
||||
UNIT_TEST_FUNCTION_TYPE_SETUP,
|
||||
UNIT_TEST_FUNCTION_TYPE_TEARDOWN,
|
||||
} UnitTestFunctionType;
|
||||
|
||||
/* Stores a unit test function with its name and type.
|
||||
* NOTE: Every setup function must be paired with a teardown function. It's
|
||||
* possible to specify NULL function pointers.
|
||||
*/
|
||||
typedef struct UnitTest {
|
||||
const char* name;
|
||||
UnitTestFunction function;
|
||||
UnitTestFunctionType function_type;
|
||||
} UnitTest;
|
||||
|
||||
|
||||
// Location within some source code.
|
||||
typedef struct SourceLocation {
|
||||
const char* file;
|
||||
int line;
|
||||
} SourceLocation;
|
||||
|
||||
// Event that's called to check a parameter value.
|
||||
typedef struct CheckParameterEvent {
|
||||
SourceLocation location;
|
||||
const char *parameter_name;
|
||||
CheckParameterValue check_value;
|
||||
LargestIntegralType check_value_data;
|
||||
} CheckParameterEvent;
|
||||
|
||||
// Used by expect_assert_failure() and mock_assert().
|
||||
extern int global_expecting_assert;
|
||||
extern jmp_buf global_expect_assert_env;
|
||||
|
||||
// Retrieves a value for the given function, as set by "will_return".
|
||||
LargestIntegralType _mock(const char * const function, const char* const file,
|
||||
const int line);
|
||||
|
||||
void _expect_check(
|
||||
const char* const function, const char* const parameter,
|
||||
const char* const file, const int line,
|
||||
const CheckParameterValue check_function,
|
||||
const LargestIntegralType check_data, CheckParameterEvent * const event,
|
||||
const int count);
|
||||
|
||||
void _expect_in_set(
|
||||
const char* const function, const char* const parameter,
|
||||
const char* const file, const int line, const LargestIntegralType values[],
|
||||
const size_t number_of_values, const int count);
|
||||
void _expect_not_in_set(
|
||||
const char* const function, const char* const parameter,
|
||||
const char* const file, const int line, const LargestIntegralType values[],
|
||||
const size_t number_of_values, const int count);
|
||||
|
||||
void _expect_in_range(
|
||||
const char* const function, const char* const parameter,
|
||||
const char* const file, const int line,
|
||||
const LargestIntegralType minimum,
|
||||
const LargestIntegralType maximum, const int count);
|
||||
void _expect_not_in_range(
|
||||
const char* const function, const char* const parameter,
|
||||
const char* const file, const int line,
|
||||
const LargestIntegralType minimum,
|
||||
const LargestIntegralType maximum, const int count);
|
||||
|
||||
void _expect_value(
|
||||
const char* const function, const char* const parameter,
|
||||
const char* const file, const int line, const LargestIntegralType value,
|
||||
const int count);
|
||||
void _expect_not_value(
|
||||
const char* const function, const char* const parameter,
|
||||
const char* const file, const int line, const LargestIntegralType value,
|
||||
const int count);
|
||||
|
||||
void _expect_string(
|
||||
const char* const function, const char* const parameter,
|
||||
const char* const file, const int line, const char* string,
|
||||
const int count);
|
||||
void _expect_not_string(
|
||||
const char* const function, const char* const parameter,
|
||||
const char* const file, const int line, const char* string,
|
||||
const int count);
|
||||
|
||||
void _expect_memory(
|
||||
const char* const function, const char* const parameter,
|
||||
const char* const file, const int line, const void* const memory,
|
||||
const size_t size, const int count);
|
||||
void _expect_not_memory(
|
||||
const char* const function, const char* const parameter,
|
||||
const char* const file, const int line, const void* const memory,
|
||||
const size_t size, const int count);
|
||||
|
||||
void _expect_any(
|
||||
const char* const function, const char* const parameter,
|
||||
const char* const file, const int line, const int count);
|
||||
|
||||
void _check_expected(
|
||||
const char * const function_name, const char * const parameter_name,
|
||||
const char* file, const int line, const LargestIntegralType value);
|
||||
|
||||
// Can be used to replace assert in tested code so that in conjuction with
|
||||
// check_assert() it's possible to determine whether an assert condition has
|
||||
// failed without stopping a test.
|
||||
void mock_assert(const int result, const char* const expression,
|
||||
const char * const file, const int line);
|
||||
|
||||
void _will_return(const char * const function_name, const char * const file,
|
||||
const int line, const LargestIntegralType value,
|
||||
const int count);
|
||||
void _assert_true(const LargestIntegralType result,
|
||||
const char* const expression,
|
||||
const char * const file, const int line);
|
||||
void _assert_int_equal(
|
||||
const LargestIntegralType a, const LargestIntegralType b,
|
||||
const char * const file, const int line);
|
||||
void _assert_int_not_equal(
|
||||
const LargestIntegralType a, const LargestIntegralType b,
|
||||
const char * const file, const int line);
|
||||
void _assert_string_equal(const char * const a, const char * const b,
|
||||
const char * const file, const int line);
|
||||
void _assert_string_not_equal(const char * const a, const char * const b,
|
||||
const char *file, const int line);
|
||||
void _assert_memory_equal(const void * const a, const void * const b,
|
||||
const size_t size, const char* const file,
|
||||
const int line);
|
||||
void _assert_memory_not_equal(const void * const a, const void * const b,
|
||||
const size_t size, const char* const file,
|
||||
const int line);
|
||||
void _assert_in_range(
|
||||
const LargestIntegralType value, const LargestIntegralType minimum,
|
||||
const LargestIntegralType maximum, const char* const file, const int line);
|
||||
void _assert_not_in_range(
|
||||
const LargestIntegralType value, const LargestIntegralType minimum,
|
||||
const LargestIntegralType maximum, const char* const file, const int line);
|
||||
void _assert_in_set(
|
||||
const LargestIntegralType value, const LargestIntegralType values[],
|
||||
const size_t number_of_values, const char* const file, const int line);
|
||||
void _assert_not_in_set(
|
||||
const LargestIntegralType value, const LargestIntegralType values[],
|
||||
const size_t number_of_values, const char* const file, const int line);
|
||||
|
||||
void* _test_malloc(const size_t size, const char* file, const int line);
|
||||
void* _test_memalign(const size_t alignment, const size_t size, const char* file, const int line);
|
||||
void* _test_calloc(const size_t number_of_elements, const size_t size,
|
||||
const char* file, const int line);
|
||||
void _test_free(void* const ptr, const char* file, const int line);
|
||||
|
||||
void _fail(const char * const file, const int line);
|
||||
int _run_test(
|
||||
const char * const function_name, const UnitTestFunction Function,
|
||||
void ** const state, const UnitTestFunctionType function_type,
|
||||
const void* const heap_check_point);
|
||||
int _run_tests(const UnitTest * const tests, const size_t number_of_tests);
|
||||
|
||||
// Standard output and error print methods.
|
||||
void print_message(const char* const format, ...);
|
||||
void print_error(const char* const format, ...);
|
||||
void vprint_message(const char* const format, va_list args);
|
||||
void vprint_error(const char* const format, va_list args);
|
||||
|
||||
#endif // CMOCKERY_H_
|
||||
7
enclave/include/curve25519-donna.h
Normal file
7
enclave/include/curve25519-donna.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef _CURVE25519_DONNA_H
|
||||
#define _CURVE25519_DONNA_H
|
||||
|
||||
int curve25519_donna(unsigned char *, const unsigned char *, const unsigned char *);
|
||||
|
||||
#endif
|
||||
|
||||
37
enclave/include/dlmalloc.h
Normal file
37
enclave/include/dlmalloc.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef _DLMALLOC_H
|
||||
#define _DLMALLOC_H
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
struct mallinfo dlmallinfo();
|
||||
struct mallinfo {
|
||||
int arena; /* non-mmapped space allocated from system */
|
||||
int ordblks; /* number of free chunks */
|
||||
int smblks; /* always 0 */
|
||||
int hblks; /* always 0 */
|
||||
int hblkhd; /* space in mmapped regions */
|
||||
int usmblks; /* maximum total allocated space */
|
||||
int fsmblks; /* always 0 */
|
||||
int uordblks; /* total allocated space */
|
||||
int fordblks; /* total free space */
|
||||
int keepcost; /* releasable (via malloc_trim) space */
|
||||
};
|
||||
|
||||
#endif
|
||||
473
enclave/include/kbupd.proto
Normal file
473
enclave/include/kbupd.proto
Normal file
@ -0,0 +1,473 @@
|
||||
syntax = "proto2";
|
||||
|
||||
package protobufs.kbupd;
|
||||
|
||||
import "kbupd_client.proto";
|
||||
|
||||
//
|
||||
// shared types
|
||||
//
|
||||
|
||||
message ServiceId {
|
||||
required bytes id = 1;
|
||||
}
|
||||
|
||||
message BackupId {
|
||||
required bytes id = 1;
|
||||
}
|
||||
|
||||
message PartitionKeyRangePB {
|
||||
required BackupId first = 1;
|
||||
required BackupId last = 2;
|
||||
}
|
||||
|
||||
message IasReport {
|
||||
required bytes body = 2;
|
||||
required bytes signature = 3;
|
||||
repeated bytes certificates = 4;
|
||||
}
|
||||
|
||||
message AttestationParameters {
|
||||
required uint64 unix_timestamp_seconds = 1;
|
||||
}
|
||||
|
||||
enum XferControlCommand {
|
||||
START = 1;
|
||||
FINISH = 2;
|
||||
CANCEL = 3;
|
||||
PAUSE = 4;
|
||||
RESUME = 5;
|
||||
}
|
||||
|
||||
//
|
||||
// transaction requests
|
||||
//
|
||||
|
||||
message CreateBackupRequest {
|
||||
required BackupId backup_id = 1;
|
||||
}
|
||||
|
||||
message CreateBackupReply {
|
||||
required bytes nonce = 2;
|
||||
optional uint32 tries = 3;
|
||||
}
|
||||
|
||||
message DeleteBackupRequest {
|
||||
required BackupId backup_id = 1;
|
||||
}
|
||||
|
||||
message DeleteBackupReply {
|
||||
}
|
||||
|
||||
//
|
||||
// untrusted messages
|
||||
//
|
||||
|
||||
message UntrustedMessageBatch {
|
||||
repeated UntrustedMessage messages = 1;
|
||||
}
|
||||
|
||||
message UntrustedMessage {
|
||||
oneof inner {
|
||||
StartFrontendRequest start_frontend_request = 1;
|
||||
StartReplicaRequest start_replica_request = 2;
|
||||
StartReplicaGroupRequest start_replica_group_request = 3;
|
||||
UntrustedTransactionRequest untrusted_transaction_request = 4;
|
||||
UntrustedXferRequest untrusted_xfer_request = 5;
|
||||
GetEnclaveStatusRequest get_enclave_status_request = 6;
|
||||
|
||||
GetQeInfoReply get_qe_info_reply = 8;
|
||||
GetQuoteReply get_quote_reply = 9;
|
||||
GetAttestationReply get_attestation_reply = 10;
|
||||
|
||||
NewMessageSignal new_message_signal = 11;
|
||||
TimerTickSignal timer_tick_signal = 12;
|
||||
SetFrontendConfigSignal set_frontend_config_signal = 13;
|
||||
SetReplicaConfigSignal set_replica_config_signal = 14;
|
||||
ResetPeerSignal reset_peer_signal = 15;
|
||||
SetVerboseLoggingSignal set_verbose_logging_signal = 16;
|
||||
}
|
||||
reserved 7;
|
||||
}
|
||||
|
||||
message PartitionConfig {
|
||||
required bytes group_id = 1;
|
||||
optional PartitionKeyRangePB range = 2;
|
||||
repeated bytes node_ids = 3;
|
||||
}
|
||||
|
||||
message StartFrontendRequest {
|
||||
repeated PartitionConfig partitions = 1;
|
||||
required EnclaveFrontendConfig config = 2;
|
||||
}
|
||||
|
||||
message EnclaveFrontendConfig {
|
||||
required uint32 replica_timeout_ticks = 1;
|
||||
required uint32 request_quote_ticks = 2;
|
||||
required uint32 min_connect_timeout_ticks = 3;
|
||||
required uint32 max_connect_timeout_ticks = 4;
|
||||
required uint32 pending_request_count = 5;
|
||||
required uint32 pending_request_ttl = 6;
|
||||
}
|
||||
|
||||
message SourcePartitionConfig {
|
||||
required PartitionKeyRangePB range = 1;
|
||||
repeated bytes node_ids = 2;
|
||||
}
|
||||
|
||||
message StartReplicaRequest {
|
||||
required EnclaveReplicaConfig config = 1;
|
||||
}
|
||||
|
||||
message EnclaveReplicaConfig {
|
||||
required uint32 election_timeout_ticks = 1;
|
||||
required uint32 heartbeat_timeout_ticks = 2;
|
||||
required uint32 request_quote_ticks = 3;
|
||||
required uint32 min_connect_timeout_ticks = 4;
|
||||
required uint32 max_connect_timeout_ticks = 5;
|
||||
required uint32 attestation_expiry_ticks = 6;
|
||||
required uint32 replication_chunk_size = 7;
|
||||
required uint32 transfer_chunk_size = 8;
|
||||
required uint32 storage_page_cache_size = 10;
|
||||
required uint32 raft_log_index_page_cache_size = 13;
|
||||
required uint32 max_frontend_count = 14;
|
||||
}
|
||||
|
||||
message StartReplicaGroupRequest {
|
||||
repeated bytes peer_node_ids = 1;
|
||||
required EnclaveReplicaGroupConfig config = 2;
|
||||
optional SourcePartitionConfig source_partition = 3;
|
||||
}
|
||||
|
||||
message EnclaveReplicaGroupConfig {
|
||||
required uint32 storage_size = 1;
|
||||
required uint64 raft_log_data_size = 2;
|
||||
required uint32 raft_log_index_size = 3;
|
||||
}
|
||||
|
||||
message NewMessageSignal {
|
||||
required bytes node_id = 1;
|
||||
required bytes data = 2;
|
||||
required bool syn = 3;
|
||||
}
|
||||
|
||||
message TimerTickSignal {
|
||||
required fixed64 now_secs = 1;
|
||||
}
|
||||
|
||||
message SetFrontendConfigSignal {
|
||||
required EnclaveFrontendConfig config = 1;
|
||||
}
|
||||
|
||||
message SetReplicaConfigSignal {
|
||||
required EnclaveReplicaConfig config = 1;
|
||||
}
|
||||
|
||||
message ResetPeerSignal {
|
||||
required bytes peer_node_id = 1;
|
||||
}
|
||||
|
||||
message SetVerboseLoggingSignal {
|
||||
required bool verbose_logging = 1;
|
||||
}
|
||||
|
||||
message GetQeInfoReply {
|
||||
required bytes mrenclave = 1;
|
||||
required uint64 flags = 2;
|
||||
required uint64 xfrm = 3;
|
||||
required uint32 misc_select = 4;
|
||||
required uint32 config_svn = 5;
|
||||
required bytes config_id = 6;
|
||||
}
|
||||
|
||||
message GetQuoteReply {
|
||||
required bytes request_id = 1;
|
||||
required bytes sgx_quote = 2;
|
||||
}
|
||||
|
||||
message GetAttestationReply {
|
||||
required bytes request_id = 1;
|
||||
required IasReport ias_report = 2;
|
||||
}
|
||||
|
||||
message UntrustedTransactionRequest {
|
||||
required uint64 request_id = 1;
|
||||
oneof data {
|
||||
CreateBackupRequest create_backup_request = 2;
|
||||
DeleteBackupRequest delete_backup_request = 3;
|
||||
};
|
||||
}
|
||||
|
||||
message UntrustedXferRequest {
|
||||
required uint64 request_id = 1;
|
||||
oneof data {
|
||||
XferControlCommand xfer_control_command = 2;
|
||||
};
|
||||
}
|
||||
|
||||
message GetEnclaveStatusRequest {
|
||||
required bool memory_status = 1;
|
||||
}
|
||||
|
||||
//
|
||||
// enclave messages
|
||||
//
|
||||
|
||||
message EnclaveMessageBatch {
|
||||
repeated EnclaveMessage messages = 1;
|
||||
}
|
||||
|
||||
message EnclaveMessage {
|
||||
oneof inner {
|
||||
StartFrontendReply start_frontend_reply = 1;
|
||||
StartReplicaReply start_replica_reply = 2;
|
||||
StartReplicaGroupReply start_replica_group_reply = 3;
|
||||
UntrustedTransactionReply untrusted_transaction_reply = 4;
|
||||
UntrustedXferReply untrusted_xfer_reply = 5;
|
||||
GetEnclaveStatusReply get_enclave_status_reply = 6;
|
||||
|
||||
SendMessageRequest send_message_request = 7;
|
||||
GetQeInfoRequest get_qe_info_request = 8;
|
||||
GetQuoteRequest get_quote_request = 9;
|
||||
GetAttestationRequest get_attestation_request = 10;
|
||||
|
||||
EnclaveLogSignal enclave_log_signal = 11;
|
||||
EnclaveTransactionSignal enclave_transaction_signal = 12;
|
||||
}
|
||||
}
|
||||
|
||||
message StartFrontendReply {
|
||||
required bytes node_id = 1;
|
||||
}
|
||||
|
||||
message StartReplicaReply {
|
||||
required bytes node_id = 1;
|
||||
}
|
||||
|
||||
message StartReplicaGroupReply {
|
||||
optional ServiceId service_id = 1;
|
||||
optional bytes group_id = 2;
|
||||
}
|
||||
|
||||
message GetEnclaveStatusReply {
|
||||
oneof inner {
|
||||
EnclaveReplicaStatus replica_status = 1;
|
||||
EnclaveFrontendStatus frontend_status = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message SendMessageRequest {
|
||||
required bytes node_id = 1;
|
||||
required bytes data = 2;
|
||||
required bool syn = 3;
|
||||
optional bytes debug_msg = 4;
|
||||
}
|
||||
|
||||
message GetQeInfoRequest {
|
||||
}
|
||||
|
||||
message GetQuoteRequest {
|
||||
required bytes request_id = 1;
|
||||
required bytes sgx_report = 2;
|
||||
}
|
||||
|
||||
message GetAttestationRequest {
|
||||
required bytes request_id = 1;
|
||||
required bytes sgx_quote = 2;
|
||||
}
|
||||
|
||||
message UntrustedTransactionReply {
|
||||
required uint64 request_id = 1;
|
||||
oneof data {
|
||||
CreateBackupReply create_backup_reply = 2;
|
||||
DeleteBackupReply delete_backup_reply = 3;
|
||||
};
|
||||
}
|
||||
|
||||
enum UntrustedXferReplyStatus {
|
||||
UNKNOWN = 0;
|
||||
OK = 1;
|
||||
NOT_LEADER = 2;
|
||||
INVALID_STATE = 3;
|
||||
}
|
||||
|
||||
message UntrustedXferReply {
|
||||
required uint64 request_id = 1;
|
||||
required UntrustedXferReplyStatus status = 2;
|
||||
}
|
||||
|
||||
enum EnclaveLogLevel {
|
||||
ERROR = 0;
|
||||
WARN = 1;
|
||||
INFO = 2;
|
||||
DEBUG = 3;
|
||||
}
|
||||
|
||||
message EnclaveLogSignal {
|
||||
required bytes message = 1;
|
||||
required bytes module = 2;
|
||||
required bytes file = 3;
|
||||
required uint32 line = 4;
|
||||
required EnclaveLogLevel level = 5;
|
||||
}
|
||||
|
||||
message EnclaveTransactionSignal {
|
||||
required uint64 log_index = 1;
|
||||
oneof transaction {
|
||||
EnclaveFrontendRequestTransaction frontend_request = 2;
|
||||
EnclaveStartXferTransaction start_xfer = 3;
|
||||
EnclaveSetSidTransaction set_sid = 4;
|
||||
EnclaveRemoveChunkTransaction remove_chunk = 5;
|
||||
EnclaveApplyChunkTransaction apply_chunk = 6;
|
||||
EnclavePauseXferTransaction pause_xfer = 7;
|
||||
EnclaveResumeXferTransaction resume_xfer = 8;
|
||||
EnclaveFinishXferTransaction finish_xfer = 9;
|
||||
EnclaveSetTimeTransaction set_time = 10;
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// enclave transactions
|
||||
//
|
||||
|
||||
message EnclaveFrontendRequestTransaction {
|
||||
oneof transaction {
|
||||
EnclaveCreateBackupTransaction create = 1;
|
||||
EnclaveBackupTransaction backup = 2;
|
||||
EnclaveRestoreTransaction restore = 3;
|
||||
EnclaveDeleteBackupTransaction delete = 4;
|
||||
|
||||
EnclaveTransactionErrorXferInProgress xfer_in_progress = 5;
|
||||
EnclaveTransactionErrorWrongPartition wrong_partition = 6;
|
||||
EnclaveTransactionErrorInvalidRequest invalid_request = 7;
|
||||
EnclaveTransactionErrorInternalError internal_error = 8;
|
||||
}
|
||||
}
|
||||
message EnclaveCreateBackupTransaction {
|
||||
required BackupId backup_id = 1;
|
||||
}
|
||||
message EnclaveBackupTransaction {
|
||||
required BackupId backup_id = 1;
|
||||
required kbupd_client.BackupResponse.Status status = 2;
|
||||
}
|
||||
message EnclaveRestoreTransaction {
|
||||
required BackupId backup_id = 1;
|
||||
required kbupd_client.RestoreResponse.Status status = 2;
|
||||
}
|
||||
message EnclaveDeleteBackupTransaction {
|
||||
required BackupId backup_id = 1;
|
||||
}
|
||||
message EnclaveTransactionErrorXferInProgress {
|
||||
}
|
||||
message EnclaveTransactionErrorWrongPartition {
|
||||
required bool new_partition_unknown = 1;
|
||||
}
|
||||
message EnclaveTransactionErrorInvalidRequest {
|
||||
}
|
||||
message EnclaveTransactionErrorInternalError {
|
||||
}
|
||||
message EnclaveStartXferTransaction {
|
||||
}
|
||||
message EnclaveSetSidTransaction {
|
||||
optional ServiceId service_id = 1;
|
||||
}
|
||||
message EnclaveRemoveChunkTransaction {
|
||||
optional PartitionKeyRangePB chunk_range = 1;
|
||||
}
|
||||
message EnclaveApplyChunkTransaction {
|
||||
optional PartitionKeyRangePB chunk_range = 1;
|
||||
repeated BackupId chunk_ids = 2;
|
||||
}
|
||||
message EnclavePauseXferTransaction {
|
||||
}
|
||||
message EnclaveResumeXferTransaction {
|
||||
optional PartitionKeyRangePB chunk_range = 1;
|
||||
}
|
||||
message EnclaveFinishXferTransaction {
|
||||
}
|
||||
message EnclaveSetTimeTransaction {
|
||||
optional uint64 now_secs = 1;
|
||||
}
|
||||
|
||||
//
|
||||
// enclave status
|
||||
//
|
||||
|
||||
message EnclaveMemoryStatus {
|
||||
required uint32 footprint_bytes = 1;
|
||||
required uint32 used_bytes = 2;
|
||||
required uint32 free_chunks = 3;
|
||||
}
|
||||
|
||||
message EnclaveReplicaStatus {
|
||||
optional EnclaveMemoryStatus memory_status = 1;
|
||||
optional EnclaveReplicaPartitionStatus partition = 2;
|
||||
}
|
||||
|
||||
message EnclaveReplicaPartitionStatus {
|
||||
required bytes group_id = 1;
|
||||
optional bytes service_id = 2;
|
||||
optional PartitionKeyRangePB range = 3;
|
||||
repeated EnclavePeerStatus peers = 4;
|
||||
required AttestationParameters min_attestation = 5;
|
||||
required bool is_leader = 6;
|
||||
required uint64 current_term = 7;
|
||||
required uint64 prev_log_index = 8;
|
||||
required uint64 last_applied_index = 9;
|
||||
required uint64 commit_index = 10;
|
||||
required uint64 last_log_index = 11;
|
||||
required uint64 last_log_term = 12;
|
||||
required uint64 log_data_length = 13;
|
||||
required uint64 backup_count = 14;
|
||||
|
||||
oneof xfer_status {
|
||||
EnclaveIncomingXferStatus incoming_xfer_status = 15;
|
||||
EnclaveOutgoingXferStatus outgoing_xfer_status = 16;
|
||||
}
|
||||
}
|
||||
|
||||
message EnclavePeerStatus {
|
||||
required bytes node_id = 1;
|
||||
optional AttestationParameters attestation = 2;
|
||||
optional EnclavePeerReplicationStatus replication_status = 3;
|
||||
required bool is_leader = 4;
|
||||
required uint64 inflight_requests = 5;
|
||||
required uint64 unsent_requests = 6;
|
||||
}
|
||||
|
||||
message EnclavePeerReplicationStatus {
|
||||
required uint64 next_index = 1;
|
||||
required uint64 match_index = 2;
|
||||
optional uint64 inflight_index = 3;
|
||||
required bool probing = 4;
|
||||
}
|
||||
|
||||
message EnclaveIncomingXferStatus {
|
||||
required PartitionKeyRangePB desired_range = 1;
|
||||
repeated EnclavePeerStatus nodes = 2;
|
||||
}
|
||||
|
||||
message EnclaveOutgoingXferStatus {
|
||||
required bytes group_id = 1;
|
||||
required PartitionKeyRangePB full_xfer_range = 2;
|
||||
optional PartitionKeyRangePB current_chunk_range = 3;
|
||||
required bool paused = 4;
|
||||
optional AttestationParameters min_attestation = 5;
|
||||
repeated EnclavePeerStatus nodes = 6;
|
||||
}
|
||||
|
||||
message EnclaveFrontendStatus {
|
||||
optional EnclaveMemoryStatus memory_status = 1;
|
||||
repeated EnclaveFrontendPartitionStatus partitions = 2;
|
||||
repeated EnclaveFrontendRangeStatus ranges = 3;
|
||||
}
|
||||
|
||||
message EnclaveFrontendPartitionStatus {
|
||||
required bytes group_id = 1;
|
||||
repeated EnclavePeerStatus nodes = 2;
|
||||
}
|
||||
|
||||
message EnclaveFrontendRangeStatus {
|
||||
required PartitionKeyRangePB range = 1;
|
||||
required bytes group_id = 2;
|
||||
}
|
||||
79
enclave/include/kbupd_client.proto
Normal file
79
enclave/include/kbupd_client.proto
Normal file
@ -0,0 +1,79 @@
|
||||
syntax = "proto2";
|
||||
|
||||
package protobufs.kbupd_client;
|
||||
|
||||
message Request {
|
||||
optional BackupRequest backup = 1;
|
||||
optional RestoreRequest restore = 2;
|
||||
optional DeleteRequest delete = 3;
|
||||
}
|
||||
|
||||
message Response {
|
||||
optional BackupResponse backup = 1;
|
||||
optional RestoreResponse restore = 2;
|
||||
optional DeleteResponse delete = 3;
|
||||
}
|
||||
|
||||
//
|
||||
// backup
|
||||
//
|
||||
|
||||
message BackupRequest {
|
||||
optional bytes service_id = 1;
|
||||
optional bytes backup_id = 2;
|
||||
optional bytes nonce = 3;
|
||||
optional uint64 valid_from = 4;
|
||||
optional bytes data = 5;
|
||||
optional bytes pin = 6;
|
||||
optional uint32 tries = 7;
|
||||
}
|
||||
|
||||
message BackupResponse {
|
||||
enum Status {
|
||||
OK = 1;
|
||||
ALREADY_EXISTS = 2;
|
||||
NOT_YET_VALID = 3;
|
||||
}
|
||||
|
||||
optional Status status = 1;
|
||||
optional bytes nonce = 2;
|
||||
}
|
||||
|
||||
//
|
||||
// restore
|
||||
//
|
||||
|
||||
message RestoreRequest {
|
||||
optional bytes service_id = 1;
|
||||
optional bytes backup_id = 2;
|
||||
optional bytes nonce = 3;
|
||||
optional uint64 valid_from = 4;
|
||||
optional bytes pin = 5;
|
||||
}
|
||||
|
||||
message RestoreResponse {
|
||||
enum Status {
|
||||
OK = 1;
|
||||
NONCE_MISMATCH = 2;
|
||||
NOT_YET_VALID = 3;
|
||||
MISSING = 4;
|
||||
PIN_MISMATCH = 5;
|
||||
}
|
||||
|
||||
optional Status status = 1;
|
||||
optional bytes nonce = 2;
|
||||
optional bytes data = 3;
|
||||
optional uint32 tries = 4;
|
||||
}
|
||||
|
||||
//
|
||||
// delete
|
||||
//
|
||||
|
||||
message DeleteRequest {
|
||||
optional bytes service_id = 1;
|
||||
optional bytes backup_id = 2;
|
||||
}
|
||||
|
||||
message DeleteResponse {
|
||||
}
|
||||
16
enclave/include/kbupd_enclave.edl
Normal file
16
enclave/include/kbupd_enclave.edl
Normal file
@ -0,0 +1,16 @@
|
||||
enclave {
|
||||
include "kbupd_sgxsd_callbacks.h"
|
||||
from "sgxsd.edl" import *;
|
||||
from "sgx_tstdc.edl" import *;
|
||||
|
||||
trusted {
|
||||
public void kbupd_enclave_recv_untrusted_msg
|
||||
([in, size=data_size] const uint8_t *data, size_t data_size);
|
||||
};
|
||||
untrusted {
|
||||
void kbupd_enclave_ocall_recv_enclave_msg
|
||||
([in, size=data_size] const uint8_t *data, size_t data_size);
|
||||
void *kbupd_enclave_ocall_alloc([in, out] size_t *size);
|
||||
void kbupd_enclave_ocall_panic([in, size=msg_size] const uint8_t *msg, size_t msg_size);
|
||||
};
|
||||
};
|
||||
949
enclave/include/kbupd_enclave_t.c
Normal file
949
enclave/include/kbupd_enclave_t.c
Normal file
@ -0,0 +1,949 @@
|
||||
#include "kbupd_enclave_t.h"
|
||||
|
||||
#include "sgx_trts.h" /* for sgx_ocalloc, sgx_is_outside_enclave */
|
||||
#include "sgx_lfence.h" /* for sgx_lfence */
|
||||
|
||||
#include <errno.h>
|
||||
#include <mbusafecrt.h> /* for memcpy_s etc */
|
||||
#include <stdlib.h> /* for malloc/free etc */
|
||||
|
||||
#define CHECK_REF_POINTER(ptr, siz) do { \
|
||||
if (!(ptr) || ! sgx_is_outside_enclave((ptr), (siz))) \
|
||||
return SGX_ERROR_INVALID_PARAMETER;\
|
||||
} while (0)
|
||||
|
||||
#define CHECK_UNIQUE_POINTER(ptr, siz) do { \
|
||||
if ((ptr) && ! sgx_is_outside_enclave((ptr), (siz))) \
|
||||
return SGX_ERROR_INVALID_PARAMETER;\
|
||||
} while (0)
|
||||
|
||||
#define CHECK_ENCLAVE_POINTER(ptr, siz) do { \
|
||||
if ((ptr) && ! sgx_is_within_enclave((ptr), (siz))) \
|
||||
return SGX_ERROR_INVALID_PARAMETER;\
|
||||
} while (0)
|
||||
|
||||
#define ADD_ASSIGN_OVERFLOW(a, b) ( \
|
||||
((a) += (b)) < (b) \
|
||||
)
|
||||
|
||||
|
||||
typedef struct ms_kbupd_enclave_recv_untrusted_msg_t {
|
||||
const uint8_t* ms_data;
|
||||
size_t ms_data_size;
|
||||
} ms_kbupd_enclave_recv_untrusted_msg_t;
|
||||
|
||||
typedef struct ms_sgxsd_enclave_node_init_t {
|
||||
sgx_status_t ms_retval;
|
||||
const sgxsd_node_init_args_t* ms_p_args;
|
||||
} ms_sgxsd_enclave_node_init_t;
|
||||
|
||||
typedef struct ms_sgxsd_enclave_get_next_report_t {
|
||||
sgx_status_t ms_retval;
|
||||
sgx_target_info_t ms_qe_target_info;
|
||||
sgx_report_t* ms_p_report;
|
||||
} ms_sgxsd_enclave_get_next_report_t;
|
||||
|
||||
typedef struct ms_sgxsd_enclave_set_current_quote_t {
|
||||
sgx_status_t ms_retval;
|
||||
} ms_sgxsd_enclave_set_current_quote_t;
|
||||
|
||||
typedef struct ms_sgxsd_enclave_negotiate_request_t {
|
||||
sgx_status_t ms_retval;
|
||||
const sgxsd_request_negotiation_request_t* ms_p_request;
|
||||
sgxsd_request_negotiation_response_t* ms_p_response;
|
||||
} ms_sgxsd_enclave_negotiate_request_t;
|
||||
|
||||
typedef struct ms_sgxsd_enclave_server_start_t {
|
||||
sgx_status_t ms_retval;
|
||||
const sgxsd_server_init_args_t* ms_p_args;
|
||||
sgxsd_server_state_handle_t ms_state_handle;
|
||||
} ms_sgxsd_enclave_server_start_t;
|
||||
|
||||
typedef struct ms_sgxsd_enclave_server_call_t {
|
||||
sgx_status_t ms_retval;
|
||||
const sgxsd_server_handle_call_args_t* ms_p_args;
|
||||
const sgxsd_msg_header_t* ms_msg_header;
|
||||
uint8_t* ms_msg_data;
|
||||
size_t ms_msg_size;
|
||||
sgxsd_msg_tag_t ms_msg_tag;
|
||||
sgxsd_server_state_handle_t ms_state_handle;
|
||||
} ms_sgxsd_enclave_server_call_t;
|
||||
|
||||
typedef struct ms_sgxsd_enclave_server_stop_t {
|
||||
sgx_status_t ms_retval;
|
||||
const sgxsd_server_terminate_args_t* ms_p_args;
|
||||
sgxsd_server_state_handle_t ms_state_handle;
|
||||
} ms_sgxsd_enclave_server_stop_t;
|
||||
|
||||
typedef struct ms_kbupd_enclave_ocall_recv_enclave_msg_t {
|
||||
const uint8_t* ms_data;
|
||||
size_t ms_data_size;
|
||||
} ms_kbupd_enclave_ocall_recv_enclave_msg_t;
|
||||
|
||||
typedef struct ms_kbupd_enclave_ocall_alloc_t {
|
||||
void* ms_retval;
|
||||
size_t* ms_size;
|
||||
} ms_kbupd_enclave_ocall_alloc_t;
|
||||
|
||||
typedef struct ms_kbupd_enclave_ocall_panic_t {
|
||||
const uint8_t* ms_msg;
|
||||
size_t ms_msg_size;
|
||||
} ms_kbupd_enclave_ocall_panic_t;
|
||||
|
||||
typedef struct ms_sgxsd_ocall_reply_t {
|
||||
sgx_status_t ms_retval;
|
||||
const sgxsd_msg_header_t* ms_reply_header;
|
||||
const uint8_t* ms_reply_data;
|
||||
size_t ms_reply_data_size;
|
||||
sgxsd_msg_tag_t ms_msg_tag;
|
||||
} ms_sgxsd_ocall_reply_t;
|
||||
|
||||
typedef struct ms_sgx_oc_cpuidex_t {
|
||||
int* ms_cpuinfo;
|
||||
int ms_leaf;
|
||||
int ms_subleaf;
|
||||
} ms_sgx_oc_cpuidex_t;
|
||||
|
||||
typedef struct ms_sgx_thread_wait_untrusted_event_ocall_t {
|
||||
int ms_retval;
|
||||
const void* ms_self;
|
||||
} ms_sgx_thread_wait_untrusted_event_ocall_t;
|
||||
|
||||
typedef struct ms_sgx_thread_set_untrusted_event_ocall_t {
|
||||
int ms_retval;
|
||||
const void* ms_waiter;
|
||||
} ms_sgx_thread_set_untrusted_event_ocall_t;
|
||||
|
||||
typedef struct ms_sgx_thread_setwait_untrusted_events_ocall_t {
|
||||
int ms_retval;
|
||||
const void* ms_waiter;
|
||||
const void* ms_self;
|
||||
} ms_sgx_thread_setwait_untrusted_events_ocall_t;
|
||||
|
||||
typedef struct ms_sgx_thread_set_multiple_untrusted_events_ocall_t {
|
||||
int ms_retval;
|
||||
const void** ms_waiters;
|
||||
size_t ms_total;
|
||||
} ms_sgx_thread_set_multiple_untrusted_events_ocall_t;
|
||||
|
||||
static sgx_status_t SGX_CDECL sgx_kbupd_enclave_recv_untrusted_msg(void* pms)
|
||||
{
|
||||
CHECK_REF_POINTER(pms, sizeof(ms_kbupd_enclave_recv_untrusted_msg_t));
|
||||
//
|
||||
// fence after pointer checks
|
||||
//
|
||||
sgx_lfence();
|
||||
ms_kbupd_enclave_recv_untrusted_msg_t* ms = SGX_CAST(ms_kbupd_enclave_recv_untrusted_msg_t*, pms);
|
||||
sgx_status_t status = SGX_SUCCESS;
|
||||
const uint8_t* _tmp_data = ms->ms_data;
|
||||
size_t _tmp_data_size = ms->ms_data_size;
|
||||
size_t _len_data = _tmp_data_size;
|
||||
uint8_t* _in_data = NULL;
|
||||
|
||||
CHECK_UNIQUE_POINTER(_tmp_data, _len_data);
|
||||
|
||||
//
|
||||
// fence after pointer checks
|
||||
//
|
||||
sgx_lfence();
|
||||
|
||||
if (_tmp_data != NULL && _len_data != 0) {
|
||||
if ( _len_data % sizeof(*_tmp_data) != 0)
|
||||
{
|
||||
status = SGX_ERROR_INVALID_PARAMETER;
|
||||
goto err;
|
||||
}
|
||||
_in_data = (uint8_t*)malloc(_len_data);
|
||||
if (_in_data == NULL) {
|
||||
status = SGX_ERROR_OUT_OF_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (memcpy_s(_in_data, _len_data, _tmp_data, _len_data)) {
|
||||
status = SGX_ERROR_UNEXPECTED;
|
||||
goto err;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
kbupd_enclave_recv_untrusted_msg((const uint8_t*)_in_data, _tmp_data_size);
|
||||
|
||||
err:
|
||||
if (_in_data) free(_in_data);
|
||||
return status;
|
||||
}
|
||||
|
||||
static sgx_status_t SGX_CDECL sgx_sgxsd_enclave_node_init(void* pms)
|
||||
{
|
||||
CHECK_REF_POINTER(pms, sizeof(ms_sgxsd_enclave_node_init_t));
|
||||
//
|
||||
// fence after pointer checks
|
||||
//
|
||||
sgx_lfence();
|
||||
ms_sgxsd_enclave_node_init_t* ms = SGX_CAST(ms_sgxsd_enclave_node_init_t*, pms);
|
||||
sgx_status_t status = SGX_SUCCESS;
|
||||
const sgxsd_node_init_args_t* _tmp_p_args = ms->ms_p_args;
|
||||
size_t _len_p_args = sizeof(sgxsd_node_init_args_t);
|
||||
sgxsd_node_init_args_t* _in_p_args = NULL;
|
||||
|
||||
CHECK_UNIQUE_POINTER(_tmp_p_args, _len_p_args);
|
||||
|
||||
//
|
||||
// fence after pointer checks
|
||||
//
|
||||
sgx_lfence();
|
||||
|
||||
if (_tmp_p_args != NULL && _len_p_args != 0) {
|
||||
_in_p_args = (sgxsd_node_init_args_t*)malloc(_len_p_args);
|
||||
if (_in_p_args == NULL) {
|
||||
status = SGX_ERROR_OUT_OF_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (memcpy_s(_in_p_args, _len_p_args, _tmp_p_args, _len_p_args)) {
|
||||
status = SGX_ERROR_UNEXPECTED;
|
||||
goto err;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ms->ms_retval = sgxsd_enclave_node_init((const sgxsd_node_init_args_t*)_in_p_args);
|
||||
|
||||
err:
|
||||
if (_in_p_args) free(_in_p_args);
|
||||
return status;
|
||||
}
|
||||
|
||||
static sgx_status_t SGX_CDECL sgx_sgxsd_enclave_get_next_report(void* pms)
|
||||
{
|
||||
CHECK_REF_POINTER(pms, sizeof(ms_sgxsd_enclave_get_next_report_t));
|
||||
//
|
||||
// fence after pointer checks
|
||||
//
|
||||
sgx_lfence();
|
||||
ms_sgxsd_enclave_get_next_report_t* ms = SGX_CAST(ms_sgxsd_enclave_get_next_report_t*, pms);
|
||||
sgx_status_t status = SGX_SUCCESS;
|
||||
sgx_report_t* _tmp_p_report = ms->ms_p_report;
|
||||
size_t _len_p_report = sizeof(sgx_report_t);
|
||||
sgx_report_t* _in_p_report = NULL;
|
||||
|
||||
CHECK_UNIQUE_POINTER(_tmp_p_report, _len_p_report);
|
||||
|
||||
//
|
||||
// fence after pointer checks
|
||||
//
|
||||
sgx_lfence();
|
||||
|
||||
if (_tmp_p_report != NULL && _len_p_report != 0) {
|
||||
if ((_in_p_report = (sgx_report_t*)malloc(_len_p_report)) == NULL) {
|
||||
status = SGX_ERROR_OUT_OF_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
|
||||
memset((void*)_in_p_report, 0, _len_p_report);
|
||||
}
|
||||
|
||||
ms->ms_retval = sgxsd_enclave_get_next_report(ms->ms_qe_target_info, _in_p_report);
|
||||
if (_in_p_report) {
|
||||
if (memcpy_s(_tmp_p_report, _len_p_report, _in_p_report, _len_p_report)) {
|
||||
status = SGX_ERROR_UNEXPECTED;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
if (_in_p_report) free(_in_p_report);
|
||||
return status;
|
||||
}
|
||||
|
||||
static sgx_status_t SGX_CDECL sgx_sgxsd_enclave_set_current_quote(void* pms)
|
||||
{
|
||||
CHECK_REF_POINTER(pms, sizeof(ms_sgxsd_enclave_set_current_quote_t));
|
||||
//
|
||||
// fence after pointer checks
|
||||
//
|
||||
sgx_lfence();
|
||||
ms_sgxsd_enclave_set_current_quote_t* ms = SGX_CAST(ms_sgxsd_enclave_set_current_quote_t*, pms);
|
||||
sgx_status_t status = SGX_SUCCESS;
|
||||
|
||||
|
||||
|
||||
ms->ms_retval = sgxsd_enclave_set_current_quote();
|
||||
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static sgx_status_t SGX_CDECL sgx_sgxsd_enclave_negotiate_request(void* pms)
|
||||
{
|
||||
CHECK_REF_POINTER(pms, sizeof(ms_sgxsd_enclave_negotiate_request_t));
|
||||
//
|
||||
// fence after pointer checks
|
||||
//
|
||||
sgx_lfence();
|
||||
ms_sgxsd_enclave_negotiate_request_t* ms = SGX_CAST(ms_sgxsd_enclave_negotiate_request_t*, pms);
|
||||
sgx_status_t status = SGX_SUCCESS;
|
||||
const sgxsd_request_negotiation_request_t* _tmp_p_request = ms->ms_p_request;
|
||||
size_t _len_p_request = sizeof(sgxsd_request_negotiation_request_t);
|
||||
sgxsd_request_negotiation_request_t* _in_p_request = NULL;
|
||||
sgxsd_request_negotiation_response_t* _tmp_p_response = ms->ms_p_response;
|
||||
size_t _len_p_response = sizeof(sgxsd_request_negotiation_response_t);
|
||||
sgxsd_request_negotiation_response_t* _in_p_response = NULL;
|
||||
|
||||
CHECK_UNIQUE_POINTER(_tmp_p_request, _len_p_request);
|
||||
CHECK_UNIQUE_POINTER(_tmp_p_response, _len_p_response);
|
||||
|
||||
//
|
||||
// fence after pointer checks
|
||||
//
|
||||
sgx_lfence();
|
||||
|
||||
if (_tmp_p_request != NULL && _len_p_request != 0) {
|
||||
_in_p_request = (sgxsd_request_negotiation_request_t*)malloc(_len_p_request);
|
||||
if (_in_p_request == NULL) {
|
||||
status = SGX_ERROR_OUT_OF_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (memcpy_s(_in_p_request, _len_p_request, _tmp_p_request, _len_p_request)) {
|
||||
status = SGX_ERROR_UNEXPECTED;
|
||||
goto err;
|
||||
}
|
||||
|
||||
}
|
||||
if (_tmp_p_response != NULL && _len_p_response != 0) {
|
||||
if ((_in_p_response = (sgxsd_request_negotiation_response_t*)malloc(_len_p_response)) == NULL) {
|
||||
status = SGX_ERROR_OUT_OF_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
|
||||
memset((void*)_in_p_response, 0, _len_p_response);
|
||||
}
|
||||
|
||||
ms->ms_retval = sgxsd_enclave_negotiate_request((const sgxsd_request_negotiation_request_t*)_in_p_request, _in_p_response);
|
||||
if (_in_p_response) {
|
||||
if (memcpy_s(_tmp_p_response, _len_p_response, _in_p_response, _len_p_response)) {
|
||||
status = SGX_ERROR_UNEXPECTED;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
err:
|
||||
if (_in_p_request) free(_in_p_request);
|
||||
if (_in_p_response) free(_in_p_response);
|
||||
return status;
|
||||
}
|
||||
|
||||
static sgx_status_t SGX_CDECL sgx_sgxsd_enclave_server_start(void* pms)
|
||||
{
|
||||
CHECK_REF_POINTER(pms, sizeof(ms_sgxsd_enclave_server_start_t));
|
||||
//
|
||||
// fence after pointer checks
|
||||
//
|
||||
sgx_lfence();
|
||||
ms_sgxsd_enclave_server_start_t* ms = SGX_CAST(ms_sgxsd_enclave_server_start_t*, pms);
|
||||
sgx_status_t status = SGX_SUCCESS;
|
||||
const sgxsd_server_init_args_t* _tmp_p_args = ms->ms_p_args;
|
||||
size_t _len_p_args = sizeof(sgxsd_server_init_args_t);
|
||||
sgxsd_server_init_args_t* _in_p_args = NULL;
|
||||
|
||||
CHECK_UNIQUE_POINTER(_tmp_p_args, _len_p_args);
|
||||
|
||||
//
|
||||
// fence after pointer checks
|
||||
//
|
||||
sgx_lfence();
|
||||
|
||||
if (_tmp_p_args != NULL && _len_p_args != 0) {
|
||||
_in_p_args = (sgxsd_server_init_args_t*)malloc(_len_p_args);
|
||||
if (_in_p_args == NULL) {
|
||||
status = SGX_ERROR_OUT_OF_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (memcpy_s(_in_p_args, _len_p_args, _tmp_p_args, _len_p_args)) {
|
||||
status = SGX_ERROR_UNEXPECTED;
|
||||
goto err;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ms->ms_retval = sgxsd_enclave_server_start((const sgxsd_server_init_args_t*)_in_p_args, ms->ms_state_handle);
|
||||
|
||||
err:
|
||||
if (_in_p_args) free(_in_p_args);
|
||||
return status;
|
||||
}
|
||||
|
||||
static sgx_status_t SGX_CDECL sgx_sgxsd_enclave_server_call(void* pms)
|
||||
{
|
||||
CHECK_REF_POINTER(pms, sizeof(ms_sgxsd_enclave_server_call_t));
|
||||
//
|
||||
// fence after pointer checks
|
||||
//
|
||||
sgx_lfence();
|
||||
ms_sgxsd_enclave_server_call_t* ms = SGX_CAST(ms_sgxsd_enclave_server_call_t*, pms);
|
||||
sgx_status_t status = SGX_SUCCESS;
|
||||
const sgxsd_server_handle_call_args_t* _tmp_p_args = ms->ms_p_args;
|
||||
size_t _len_p_args = sizeof(sgxsd_server_handle_call_args_t);
|
||||
sgxsd_server_handle_call_args_t* _in_p_args = NULL;
|
||||
const sgxsd_msg_header_t* _tmp_msg_header = ms->ms_msg_header;
|
||||
size_t _len_msg_header = sizeof(sgxsd_msg_header_t);
|
||||
sgxsd_msg_header_t* _in_msg_header = NULL;
|
||||
uint8_t* _tmp_msg_data = ms->ms_msg_data;
|
||||
size_t _tmp_msg_size = ms->ms_msg_size;
|
||||
size_t _len_msg_data = _tmp_msg_size;
|
||||
uint8_t* _in_msg_data = NULL;
|
||||
|
||||
CHECK_UNIQUE_POINTER(_tmp_p_args, _len_p_args);
|
||||
CHECK_UNIQUE_POINTER(_tmp_msg_header, _len_msg_header);
|
||||
CHECK_UNIQUE_POINTER(_tmp_msg_data, _len_msg_data);
|
||||
|
||||
//
|
||||
// fence after pointer checks
|
||||
//
|
||||
sgx_lfence();
|
||||
|
||||
if (_tmp_p_args != NULL && _len_p_args != 0) {
|
||||
_in_p_args = (sgxsd_server_handle_call_args_t*)malloc(_len_p_args);
|
||||
if (_in_p_args == NULL) {
|
||||
status = SGX_ERROR_OUT_OF_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (memcpy_s(_in_p_args, _len_p_args, _tmp_p_args, _len_p_args)) {
|
||||
status = SGX_ERROR_UNEXPECTED;
|
||||
goto err;
|
||||
}
|
||||
|
||||
}
|
||||
if (_tmp_msg_header != NULL && _len_msg_header != 0) {
|
||||
_in_msg_header = (sgxsd_msg_header_t*)malloc(_len_msg_header);
|
||||
if (_in_msg_header == NULL) {
|
||||
status = SGX_ERROR_OUT_OF_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (memcpy_s(_in_msg_header, _len_msg_header, _tmp_msg_header, _len_msg_header)) {
|
||||
status = SGX_ERROR_UNEXPECTED;
|
||||
goto err;
|
||||
}
|
||||
|
||||
}
|
||||
if (_tmp_msg_data != NULL && _len_msg_data != 0) {
|
||||
if ( _len_msg_data % sizeof(*_tmp_msg_data) != 0)
|
||||
{
|
||||
status = SGX_ERROR_INVALID_PARAMETER;
|
||||
goto err;
|
||||
}
|
||||
_in_msg_data = (uint8_t*)malloc(_len_msg_data);
|
||||
if (_in_msg_data == NULL) {
|
||||
status = SGX_ERROR_OUT_OF_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (memcpy_s(_in_msg_data, _len_msg_data, _tmp_msg_data, _len_msg_data)) {
|
||||
status = SGX_ERROR_UNEXPECTED;
|
||||
goto err;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ms->ms_retval = sgxsd_enclave_server_call((const sgxsd_server_handle_call_args_t*)_in_p_args, (const sgxsd_msg_header_t*)_in_msg_header, _in_msg_data, _tmp_msg_size, ms->ms_msg_tag, ms->ms_state_handle);
|
||||
|
||||
err:
|
||||
if (_in_p_args) free(_in_p_args);
|
||||
if (_in_msg_header) free(_in_msg_header);
|
||||
if (_in_msg_data) free(_in_msg_data);
|
||||
return status;
|
||||
}
|
||||
|
||||
static sgx_status_t SGX_CDECL sgx_sgxsd_enclave_server_stop(void* pms)
|
||||
{
|
||||
CHECK_REF_POINTER(pms, sizeof(ms_sgxsd_enclave_server_stop_t));
|
||||
//
|
||||
// fence after pointer checks
|
||||
//
|
||||
sgx_lfence();
|
||||
ms_sgxsd_enclave_server_stop_t* ms = SGX_CAST(ms_sgxsd_enclave_server_stop_t*, pms);
|
||||
sgx_status_t status = SGX_SUCCESS;
|
||||
const sgxsd_server_terminate_args_t* _tmp_p_args = ms->ms_p_args;
|
||||
size_t _len_p_args = sizeof(sgxsd_server_terminate_args_t);
|
||||
sgxsd_server_terminate_args_t* _in_p_args = NULL;
|
||||
|
||||
CHECK_UNIQUE_POINTER(_tmp_p_args, _len_p_args);
|
||||
|
||||
//
|
||||
// fence after pointer checks
|
||||
//
|
||||
sgx_lfence();
|
||||
|
||||
if (_tmp_p_args != NULL && _len_p_args != 0) {
|
||||
_in_p_args = (sgxsd_server_terminate_args_t*)malloc(_len_p_args);
|
||||
if (_in_p_args == NULL) {
|
||||
status = SGX_ERROR_OUT_OF_MEMORY;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (memcpy_s(_in_p_args, _len_p_args, _tmp_p_args, _len_p_args)) {
|
||||
status = SGX_ERROR_UNEXPECTED;
|
||||
goto err;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ms->ms_retval = sgxsd_enclave_server_stop((const sgxsd_server_terminate_args_t*)_in_p_args, ms->ms_state_handle);
|
||||
|
||||
err:
|
||||
if (_in_p_args) free(_in_p_args);
|
||||
return status;
|
||||
}
|
||||
|
||||
SGX_EXTERNC const struct {
|
||||
size_t nr_ecall;
|
||||
struct {void* ecall_addr; uint8_t is_priv;} ecall_table[8];
|
||||
} g_ecall_table = {
|
||||
8,
|
||||
{
|
||||
{(void*)(uintptr_t)sgx_kbupd_enclave_recv_untrusted_msg, 0},
|
||||
{(void*)(uintptr_t)sgx_sgxsd_enclave_node_init, 0},
|
||||
{(void*)(uintptr_t)sgx_sgxsd_enclave_get_next_report, 0},
|
||||
{(void*)(uintptr_t)sgx_sgxsd_enclave_set_current_quote, 0},
|
||||
{(void*)(uintptr_t)sgx_sgxsd_enclave_negotiate_request, 0},
|
||||
{(void*)(uintptr_t)sgx_sgxsd_enclave_server_start, 0},
|
||||
{(void*)(uintptr_t)sgx_sgxsd_enclave_server_call, 0},
|
||||
{(void*)(uintptr_t)sgx_sgxsd_enclave_server_stop, 0},
|
||||
}
|
||||
};
|
||||
|
||||
SGX_EXTERNC const struct {
|
||||
size_t nr_ocall;
|
||||
uint8_t entry_table[9][8];
|
||||
} g_dyn_entry_table = {
|
||||
9,
|
||||
{
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, },
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, },
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, },
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, },
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, },
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, },
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, },
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, },
|
||||
{0, 0, 0, 0, 0, 0, 0, 0, },
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
sgx_status_t SGX_CDECL kbupd_enclave_ocall_recv_enclave_msg(const uint8_t* data, size_t data_size)
|
||||
{
|
||||
sgx_status_t status = SGX_SUCCESS;
|
||||
size_t _len_data = data_size;
|
||||
|
||||
ms_kbupd_enclave_ocall_recv_enclave_msg_t* ms = NULL;
|
||||
size_t ocalloc_size = sizeof(ms_kbupd_enclave_ocall_recv_enclave_msg_t);
|
||||
void *__tmp = NULL;
|
||||
|
||||
|
||||
CHECK_ENCLAVE_POINTER(data, _len_data);
|
||||
|
||||
if (ADD_ASSIGN_OVERFLOW(ocalloc_size, (data != NULL) ? _len_data : 0))
|
||||
return SGX_ERROR_INVALID_PARAMETER;
|
||||
|
||||
__tmp = sgx_ocalloc(ocalloc_size);
|
||||
if (__tmp == NULL) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_UNEXPECTED;
|
||||
}
|
||||
ms = (ms_kbupd_enclave_ocall_recv_enclave_msg_t*)__tmp;
|
||||
__tmp = (void *)((size_t)__tmp + sizeof(ms_kbupd_enclave_ocall_recv_enclave_msg_t));
|
||||
ocalloc_size -= sizeof(ms_kbupd_enclave_ocall_recv_enclave_msg_t);
|
||||
|
||||
if (data != NULL) {
|
||||
ms->ms_data = (const uint8_t*)__tmp;
|
||||
if (_len_data % sizeof(*data) != 0) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
if (memcpy_s(__tmp, ocalloc_size, data, _len_data)) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_UNEXPECTED;
|
||||
}
|
||||
__tmp = (void *)((size_t)__tmp + _len_data);
|
||||
ocalloc_size -= _len_data;
|
||||
} else {
|
||||
ms->ms_data = NULL;
|
||||
}
|
||||
|
||||
ms->ms_data_size = data_size;
|
||||
status = sgx_ocall(0, ms);
|
||||
|
||||
if (status == SGX_SUCCESS) {
|
||||
}
|
||||
sgx_ocfree();
|
||||
return status;
|
||||
}
|
||||
|
||||
sgx_status_t SGX_CDECL kbupd_enclave_ocall_alloc(void** retval, size_t* size)
|
||||
{
|
||||
sgx_status_t status = SGX_SUCCESS;
|
||||
size_t _len_size = sizeof(size_t);
|
||||
|
||||
ms_kbupd_enclave_ocall_alloc_t* ms = NULL;
|
||||
size_t ocalloc_size = sizeof(ms_kbupd_enclave_ocall_alloc_t);
|
||||
void *__tmp = NULL;
|
||||
|
||||
void *__tmp_size = NULL;
|
||||
|
||||
CHECK_ENCLAVE_POINTER(size, _len_size);
|
||||
|
||||
if (ADD_ASSIGN_OVERFLOW(ocalloc_size, (size != NULL) ? _len_size : 0))
|
||||
return SGX_ERROR_INVALID_PARAMETER;
|
||||
|
||||
__tmp = sgx_ocalloc(ocalloc_size);
|
||||
if (__tmp == NULL) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_UNEXPECTED;
|
||||
}
|
||||
ms = (ms_kbupd_enclave_ocall_alloc_t*)__tmp;
|
||||
__tmp = (void *)((size_t)__tmp + sizeof(ms_kbupd_enclave_ocall_alloc_t));
|
||||
ocalloc_size -= sizeof(ms_kbupd_enclave_ocall_alloc_t);
|
||||
|
||||
if (size != NULL) {
|
||||
ms->ms_size = (size_t*)__tmp;
|
||||
__tmp_size = __tmp;
|
||||
if (_len_size % sizeof(*size) != 0) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
if (memcpy_s(__tmp_size, ocalloc_size, size, _len_size)) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_UNEXPECTED;
|
||||
}
|
||||
__tmp = (void *)((size_t)__tmp + _len_size);
|
||||
ocalloc_size -= _len_size;
|
||||
} else {
|
||||
ms->ms_size = NULL;
|
||||
}
|
||||
|
||||
status = sgx_ocall(1, ms);
|
||||
|
||||
if (status == SGX_SUCCESS) {
|
||||
if (retval) *retval = ms->ms_retval;
|
||||
if (size) {
|
||||
if (memcpy_s((void*)size, _len_size, __tmp_size, _len_size)) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
sgx_ocfree();
|
||||
return status;
|
||||
}
|
||||
|
||||
sgx_status_t SGX_CDECL kbupd_enclave_ocall_panic(const uint8_t* msg, size_t msg_size)
|
||||
{
|
||||
sgx_status_t status = SGX_SUCCESS;
|
||||
size_t _len_msg = msg_size;
|
||||
|
||||
ms_kbupd_enclave_ocall_panic_t* ms = NULL;
|
||||
size_t ocalloc_size = sizeof(ms_kbupd_enclave_ocall_panic_t);
|
||||
void *__tmp = NULL;
|
||||
|
||||
|
||||
CHECK_ENCLAVE_POINTER(msg, _len_msg);
|
||||
|
||||
if (ADD_ASSIGN_OVERFLOW(ocalloc_size, (msg != NULL) ? _len_msg : 0))
|
||||
return SGX_ERROR_INVALID_PARAMETER;
|
||||
|
||||
__tmp = sgx_ocalloc(ocalloc_size);
|
||||
if (__tmp == NULL) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_UNEXPECTED;
|
||||
}
|
||||
ms = (ms_kbupd_enclave_ocall_panic_t*)__tmp;
|
||||
__tmp = (void *)((size_t)__tmp + sizeof(ms_kbupd_enclave_ocall_panic_t));
|
||||
ocalloc_size -= sizeof(ms_kbupd_enclave_ocall_panic_t);
|
||||
|
||||
if (msg != NULL) {
|
||||
ms->ms_msg = (const uint8_t*)__tmp;
|
||||
if (_len_msg % sizeof(*msg) != 0) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
if (memcpy_s(__tmp, ocalloc_size, msg, _len_msg)) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_UNEXPECTED;
|
||||
}
|
||||
__tmp = (void *)((size_t)__tmp + _len_msg);
|
||||
ocalloc_size -= _len_msg;
|
||||
} else {
|
||||
ms->ms_msg = NULL;
|
||||
}
|
||||
|
||||
ms->ms_msg_size = msg_size;
|
||||
status = sgx_ocall(2, ms);
|
||||
|
||||
if (status == SGX_SUCCESS) {
|
||||
}
|
||||
sgx_ocfree();
|
||||
return status;
|
||||
}
|
||||
|
||||
sgx_status_t SGX_CDECL sgxsd_ocall_reply(sgx_status_t* retval, const sgxsd_msg_header_t* reply_header, const uint8_t* reply_data, size_t reply_data_size, sgxsd_msg_tag_t msg_tag)
|
||||
{
|
||||
sgx_status_t status = SGX_SUCCESS;
|
||||
size_t _len_reply_header = sizeof(sgxsd_msg_header_t);
|
||||
size_t _len_reply_data = reply_data_size;
|
||||
|
||||
ms_sgxsd_ocall_reply_t* ms = NULL;
|
||||
size_t ocalloc_size = sizeof(ms_sgxsd_ocall_reply_t);
|
||||
void *__tmp = NULL;
|
||||
|
||||
|
||||
CHECK_ENCLAVE_POINTER(reply_header, _len_reply_header);
|
||||
CHECK_ENCLAVE_POINTER(reply_data, _len_reply_data);
|
||||
|
||||
if (ADD_ASSIGN_OVERFLOW(ocalloc_size, (reply_header != NULL) ? _len_reply_header : 0))
|
||||
return SGX_ERROR_INVALID_PARAMETER;
|
||||
if (ADD_ASSIGN_OVERFLOW(ocalloc_size, (reply_data != NULL) ? _len_reply_data : 0))
|
||||
return SGX_ERROR_INVALID_PARAMETER;
|
||||
|
||||
__tmp = sgx_ocalloc(ocalloc_size);
|
||||
if (__tmp == NULL) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_UNEXPECTED;
|
||||
}
|
||||
ms = (ms_sgxsd_ocall_reply_t*)__tmp;
|
||||
__tmp = (void *)((size_t)__tmp + sizeof(ms_sgxsd_ocall_reply_t));
|
||||
ocalloc_size -= sizeof(ms_sgxsd_ocall_reply_t);
|
||||
|
||||
if (reply_header != NULL) {
|
||||
ms->ms_reply_header = (const sgxsd_msg_header_t*)__tmp;
|
||||
if (memcpy_s(__tmp, ocalloc_size, reply_header, _len_reply_header)) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_UNEXPECTED;
|
||||
}
|
||||
__tmp = (void *)((size_t)__tmp + _len_reply_header);
|
||||
ocalloc_size -= _len_reply_header;
|
||||
} else {
|
||||
ms->ms_reply_header = NULL;
|
||||
}
|
||||
|
||||
if (reply_data != NULL) {
|
||||
ms->ms_reply_data = (const uint8_t*)__tmp;
|
||||
if (_len_reply_data % sizeof(*reply_data) != 0) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
if (memcpy_s(__tmp, ocalloc_size, reply_data, _len_reply_data)) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_UNEXPECTED;
|
||||
}
|
||||
__tmp = (void *)((size_t)__tmp + _len_reply_data);
|
||||
ocalloc_size -= _len_reply_data;
|
||||
} else {
|
||||
ms->ms_reply_data = NULL;
|
||||
}
|
||||
|
||||
ms->ms_reply_data_size = reply_data_size;
|
||||
ms->ms_msg_tag = msg_tag;
|
||||
status = sgx_ocall(3, ms);
|
||||
|
||||
if (status == SGX_SUCCESS) {
|
||||
if (retval) *retval = ms->ms_retval;
|
||||
}
|
||||
sgx_ocfree();
|
||||
return status;
|
||||
}
|
||||
|
||||
sgx_status_t SGX_CDECL sgx_oc_cpuidex(int cpuinfo[4], int leaf, int subleaf)
|
||||
{
|
||||
sgx_status_t status = SGX_SUCCESS;
|
||||
size_t _len_cpuinfo = 4 * sizeof(int);
|
||||
|
||||
ms_sgx_oc_cpuidex_t* ms = NULL;
|
||||
size_t ocalloc_size = sizeof(ms_sgx_oc_cpuidex_t);
|
||||
void *__tmp = NULL;
|
||||
|
||||
void *__tmp_cpuinfo = NULL;
|
||||
|
||||
CHECK_ENCLAVE_POINTER(cpuinfo, _len_cpuinfo);
|
||||
|
||||
if (ADD_ASSIGN_OVERFLOW(ocalloc_size, (cpuinfo != NULL) ? _len_cpuinfo : 0))
|
||||
return SGX_ERROR_INVALID_PARAMETER;
|
||||
|
||||
__tmp = sgx_ocalloc(ocalloc_size);
|
||||
if (__tmp == NULL) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_UNEXPECTED;
|
||||
}
|
||||
ms = (ms_sgx_oc_cpuidex_t*)__tmp;
|
||||
__tmp = (void *)((size_t)__tmp + sizeof(ms_sgx_oc_cpuidex_t));
|
||||
ocalloc_size -= sizeof(ms_sgx_oc_cpuidex_t);
|
||||
|
||||
if (cpuinfo != NULL) {
|
||||
ms->ms_cpuinfo = (int*)__tmp;
|
||||
__tmp_cpuinfo = __tmp;
|
||||
if (_len_cpuinfo % sizeof(*cpuinfo) != 0) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
memset(__tmp_cpuinfo, 0, _len_cpuinfo);
|
||||
__tmp = (void *)((size_t)__tmp + _len_cpuinfo);
|
||||
ocalloc_size -= _len_cpuinfo;
|
||||
} else {
|
||||
ms->ms_cpuinfo = NULL;
|
||||
}
|
||||
|
||||
ms->ms_leaf = leaf;
|
||||
ms->ms_subleaf = subleaf;
|
||||
status = sgx_ocall(4, ms);
|
||||
|
||||
if (status == SGX_SUCCESS) {
|
||||
if (cpuinfo) {
|
||||
if (memcpy_s((void*)cpuinfo, _len_cpuinfo, __tmp_cpuinfo, _len_cpuinfo)) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
sgx_ocfree();
|
||||
return status;
|
||||
}
|
||||
|
||||
sgx_status_t SGX_CDECL sgx_thread_wait_untrusted_event_ocall(int* retval, const void* self)
|
||||
{
|
||||
sgx_status_t status = SGX_SUCCESS;
|
||||
|
||||
ms_sgx_thread_wait_untrusted_event_ocall_t* ms = NULL;
|
||||
size_t ocalloc_size = sizeof(ms_sgx_thread_wait_untrusted_event_ocall_t);
|
||||
void *__tmp = NULL;
|
||||
|
||||
|
||||
__tmp = sgx_ocalloc(ocalloc_size);
|
||||
if (__tmp == NULL) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_UNEXPECTED;
|
||||
}
|
||||
ms = (ms_sgx_thread_wait_untrusted_event_ocall_t*)__tmp;
|
||||
__tmp = (void *)((size_t)__tmp + sizeof(ms_sgx_thread_wait_untrusted_event_ocall_t));
|
||||
ocalloc_size -= sizeof(ms_sgx_thread_wait_untrusted_event_ocall_t);
|
||||
|
||||
ms->ms_self = self;
|
||||
status = sgx_ocall(5, ms);
|
||||
|
||||
if (status == SGX_SUCCESS) {
|
||||
if (retval) *retval = ms->ms_retval;
|
||||
}
|
||||
sgx_ocfree();
|
||||
return status;
|
||||
}
|
||||
|
||||
sgx_status_t SGX_CDECL sgx_thread_set_untrusted_event_ocall(int* retval, const void* waiter)
|
||||
{
|
||||
sgx_status_t status = SGX_SUCCESS;
|
||||
|
||||
ms_sgx_thread_set_untrusted_event_ocall_t* ms = NULL;
|
||||
size_t ocalloc_size = sizeof(ms_sgx_thread_set_untrusted_event_ocall_t);
|
||||
void *__tmp = NULL;
|
||||
|
||||
|
||||
__tmp = sgx_ocalloc(ocalloc_size);
|
||||
if (__tmp == NULL) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_UNEXPECTED;
|
||||
}
|
||||
ms = (ms_sgx_thread_set_untrusted_event_ocall_t*)__tmp;
|
||||
__tmp = (void *)((size_t)__tmp + sizeof(ms_sgx_thread_set_untrusted_event_ocall_t));
|
||||
ocalloc_size -= sizeof(ms_sgx_thread_set_untrusted_event_ocall_t);
|
||||
|
||||
ms->ms_waiter = waiter;
|
||||
status = sgx_ocall(6, ms);
|
||||
|
||||
if (status == SGX_SUCCESS) {
|
||||
if (retval) *retval = ms->ms_retval;
|
||||
}
|
||||
sgx_ocfree();
|
||||
return status;
|
||||
}
|
||||
|
||||
sgx_status_t SGX_CDECL sgx_thread_setwait_untrusted_events_ocall(int* retval, const void* waiter, const void* self)
|
||||
{
|
||||
sgx_status_t status = SGX_SUCCESS;
|
||||
|
||||
ms_sgx_thread_setwait_untrusted_events_ocall_t* ms = NULL;
|
||||
size_t ocalloc_size = sizeof(ms_sgx_thread_setwait_untrusted_events_ocall_t);
|
||||
void *__tmp = NULL;
|
||||
|
||||
|
||||
__tmp = sgx_ocalloc(ocalloc_size);
|
||||
if (__tmp == NULL) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_UNEXPECTED;
|
||||
}
|
||||
ms = (ms_sgx_thread_setwait_untrusted_events_ocall_t*)__tmp;
|
||||
__tmp = (void *)((size_t)__tmp + sizeof(ms_sgx_thread_setwait_untrusted_events_ocall_t));
|
||||
ocalloc_size -= sizeof(ms_sgx_thread_setwait_untrusted_events_ocall_t);
|
||||
|
||||
ms->ms_waiter = waiter;
|
||||
ms->ms_self = self;
|
||||
status = sgx_ocall(7, ms);
|
||||
|
||||
if (status == SGX_SUCCESS) {
|
||||
if (retval) *retval = ms->ms_retval;
|
||||
}
|
||||
sgx_ocfree();
|
||||
return status;
|
||||
}
|
||||
|
||||
sgx_status_t SGX_CDECL sgx_thread_set_multiple_untrusted_events_ocall(int* retval, const void** waiters, size_t total)
|
||||
{
|
||||
sgx_status_t status = SGX_SUCCESS;
|
||||
size_t _len_waiters = total * sizeof(void*);
|
||||
|
||||
ms_sgx_thread_set_multiple_untrusted_events_ocall_t* ms = NULL;
|
||||
size_t ocalloc_size = sizeof(ms_sgx_thread_set_multiple_untrusted_events_ocall_t);
|
||||
void *__tmp = NULL;
|
||||
|
||||
|
||||
CHECK_ENCLAVE_POINTER(waiters, _len_waiters);
|
||||
|
||||
if (ADD_ASSIGN_OVERFLOW(ocalloc_size, (waiters != NULL) ? _len_waiters : 0))
|
||||
return SGX_ERROR_INVALID_PARAMETER;
|
||||
|
||||
__tmp = sgx_ocalloc(ocalloc_size);
|
||||
if (__tmp == NULL) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_UNEXPECTED;
|
||||
}
|
||||
ms = (ms_sgx_thread_set_multiple_untrusted_events_ocall_t*)__tmp;
|
||||
__tmp = (void *)((size_t)__tmp + sizeof(ms_sgx_thread_set_multiple_untrusted_events_ocall_t));
|
||||
ocalloc_size -= sizeof(ms_sgx_thread_set_multiple_untrusted_events_ocall_t);
|
||||
|
||||
if (waiters != NULL) {
|
||||
ms->ms_waiters = (const void**)__tmp;
|
||||
if (_len_waiters % sizeof(*waiters) != 0) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_INVALID_PARAMETER;
|
||||
}
|
||||
if (memcpy_s(__tmp, ocalloc_size, waiters, _len_waiters)) {
|
||||
sgx_ocfree();
|
||||
return SGX_ERROR_UNEXPECTED;
|
||||
}
|
||||
__tmp = (void *)((size_t)__tmp + _len_waiters);
|
||||
ocalloc_size -= _len_waiters;
|
||||
} else {
|
||||
ms->ms_waiters = NULL;
|
||||
}
|
||||
|
||||
ms->ms_total = total;
|
||||
status = sgx_ocall(8, ms);
|
||||
|
||||
if (status == SGX_SUCCESS) {
|
||||
if (retval) *retval = ms->ms_retval;
|
||||
}
|
||||
sgx_ocfree();
|
||||
return status;
|
||||
}
|
||||
|
||||
46
enclave/include/kbupd_enclave_t.h
Normal file
46
enclave/include/kbupd_enclave_t.h
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef KBUPD_ENCLAVE_T_H__
|
||||
#define KBUPD_ENCLAVE_T_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <wchar.h>
|
||||
#include <stddef.h>
|
||||
#include "sgx_edger8r.h" /* for sgx_ocall etc. */
|
||||
|
||||
#include "kbupd_sgxsd_callbacks.h"
|
||||
#include "stdbool.h"
|
||||
#include "sgx_quote.h"
|
||||
#include "sgx_report.h"
|
||||
#include "sgxsd.h"
|
||||
|
||||
#include <stdlib.h> /* for size_t */
|
||||
|
||||
#define SGX_CAST(type, item) ((type)(item))
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void kbupd_enclave_recv_untrusted_msg(const uint8_t* data, size_t data_size);
|
||||
sgx_status_t sgxsd_enclave_node_init(const sgxsd_node_init_args_t* p_args);
|
||||
sgx_status_t sgxsd_enclave_get_next_report(sgx_target_info_t qe_target_info, sgx_report_t* p_report);
|
||||
sgx_status_t sgxsd_enclave_set_current_quote(void);
|
||||
sgx_status_t sgxsd_enclave_negotiate_request(const sgxsd_request_negotiation_request_t* p_request, sgxsd_request_negotiation_response_t* p_response);
|
||||
sgx_status_t sgxsd_enclave_server_start(const sgxsd_server_init_args_t* p_args, sgxsd_server_state_handle_t state_handle);
|
||||
sgx_status_t sgxsd_enclave_server_call(const sgxsd_server_handle_call_args_t* p_args, const sgxsd_msg_header_t* msg_header, uint8_t* msg_data, size_t msg_size, sgxsd_msg_tag_t msg_tag, sgxsd_server_state_handle_t state_handle);
|
||||
sgx_status_t sgxsd_enclave_server_stop(const sgxsd_server_terminate_args_t* p_args, sgxsd_server_state_handle_t state_handle);
|
||||
|
||||
sgx_status_t SGX_CDECL kbupd_enclave_ocall_recv_enclave_msg(const uint8_t* data, size_t data_size);
|
||||
sgx_status_t SGX_CDECL kbupd_enclave_ocall_alloc(void** retval, size_t* size);
|
||||
sgx_status_t SGX_CDECL kbupd_enclave_ocall_panic(const uint8_t* msg, size_t msg_size);
|
||||
sgx_status_t SGX_CDECL sgxsd_ocall_reply(sgx_status_t* retval, const sgxsd_msg_header_t* reply_header, const uint8_t* reply_data, size_t reply_data_size, sgxsd_msg_tag_t msg_tag);
|
||||
sgx_status_t SGX_CDECL sgx_oc_cpuidex(int cpuinfo[4], int leaf, int subleaf);
|
||||
sgx_status_t SGX_CDECL sgx_thread_wait_untrusted_event_ocall(int* retval, const void* self);
|
||||
sgx_status_t SGX_CDECL sgx_thread_set_untrusted_event_ocall(int* retval, const void* waiter);
|
||||
sgx_status_t SGX_CDECL sgx_thread_setwait_untrusted_events_ocall(int* retval, const void* waiter, const void* self);
|
||||
sgx_status_t SGX_CDECL sgx_thread_set_multiple_untrusted_events_ocall(int* retval, const void** waiters, size_t total);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif
|
||||
279
enclave/include/kbupd_enclave_u.c
Normal file
279
enclave/include/kbupd_enclave_u.c
Normal file
@ -0,0 +1,279 @@
|
||||
#include "kbupd_enclave_u.h"
|
||||
#include <errno.h>
|
||||
|
||||
typedef struct ms_kbupd_enclave_recv_untrusted_msg_t {
|
||||
const uint8_t* ms_data;
|
||||
size_t ms_data_size;
|
||||
} ms_kbupd_enclave_recv_untrusted_msg_t;
|
||||
|
||||
typedef struct ms_sgxsd_enclave_node_init_t {
|
||||
sgx_status_t ms_retval;
|
||||
const sgxsd_node_init_args_t* ms_p_args;
|
||||
} ms_sgxsd_enclave_node_init_t;
|
||||
|
||||
typedef struct ms_sgxsd_enclave_get_next_report_t {
|
||||
sgx_status_t ms_retval;
|
||||
sgx_target_info_t ms_qe_target_info;
|
||||
sgx_report_t* ms_p_report;
|
||||
} ms_sgxsd_enclave_get_next_report_t;
|
||||
|
||||
typedef struct ms_sgxsd_enclave_set_current_quote_t {
|
||||
sgx_status_t ms_retval;
|
||||
} ms_sgxsd_enclave_set_current_quote_t;
|
||||
|
||||
typedef struct ms_sgxsd_enclave_negotiate_request_t {
|
||||
sgx_status_t ms_retval;
|
||||
const sgxsd_request_negotiation_request_t* ms_p_request;
|
||||
sgxsd_request_negotiation_response_t* ms_p_response;
|
||||
} ms_sgxsd_enclave_negotiate_request_t;
|
||||
|
||||
typedef struct ms_sgxsd_enclave_server_start_t {
|
||||
sgx_status_t ms_retval;
|
||||
const sgxsd_server_init_args_t* ms_p_args;
|
||||
sgxsd_server_state_handle_t ms_state_handle;
|
||||
} ms_sgxsd_enclave_server_start_t;
|
||||
|
||||
typedef struct ms_sgxsd_enclave_server_call_t {
|
||||
sgx_status_t ms_retval;
|
||||
const sgxsd_server_handle_call_args_t* ms_p_args;
|
||||
const sgxsd_msg_header_t* ms_msg_header;
|
||||
uint8_t* ms_msg_data;
|
||||
size_t ms_msg_size;
|
||||
sgxsd_msg_tag_t ms_msg_tag;
|
||||
sgxsd_server_state_handle_t ms_state_handle;
|
||||
} ms_sgxsd_enclave_server_call_t;
|
||||
|
||||
typedef struct ms_sgxsd_enclave_server_stop_t {
|
||||
sgx_status_t ms_retval;
|
||||
const sgxsd_server_terminate_args_t* ms_p_args;
|
||||
sgxsd_server_state_handle_t ms_state_handle;
|
||||
} ms_sgxsd_enclave_server_stop_t;
|
||||
|
||||
typedef struct ms_kbupd_enclave_ocall_recv_enclave_msg_t {
|
||||
const uint8_t* ms_data;
|
||||
size_t ms_data_size;
|
||||
} ms_kbupd_enclave_ocall_recv_enclave_msg_t;
|
||||
|
||||
typedef struct ms_kbupd_enclave_ocall_alloc_t {
|
||||
void* ms_retval;
|
||||
size_t* ms_size;
|
||||
} ms_kbupd_enclave_ocall_alloc_t;
|
||||
|
||||
typedef struct ms_kbupd_enclave_ocall_panic_t {
|
||||
const uint8_t* ms_msg;
|
||||
size_t ms_msg_size;
|
||||
} ms_kbupd_enclave_ocall_panic_t;
|
||||
|
||||
typedef struct ms_sgxsd_ocall_reply_t {
|
||||
sgx_status_t ms_retval;
|
||||
const sgxsd_msg_header_t* ms_reply_header;
|
||||
const uint8_t* ms_reply_data;
|
||||
size_t ms_reply_data_size;
|
||||
sgxsd_msg_tag_t ms_msg_tag;
|
||||
} ms_sgxsd_ocall_reply_t;
|
||||
|
||||
typedef struct ms_sgx_oc_cpuidex_t {
|
||||
int* ms_cpuinfo;
|
||||
int ms_leaf;
|
||||
int ms_subleaf;
|
||||
} ms_sgx_oc_cpuidex_t;
|
||||
|
||||
typedef struct ms_sgx_thread_wait_untrusted_event_ocall_t {
|
||||
int ms_retval;
|
||||
const void* ms_self;
|
||||
} ms_sgx_thread_wait_untrusted_event_ocall_t;
|
||||
|
||||
typedef struct ms_sgx_thread_set_untrusted_event_ocall_t {
|
||||
int ms_retval;
|
||||
const void* ms_waiter;
|
||||
} ms_sgx_thread_set_untrusted_event_ocall_t;
|
||||
|
||||
typedef struct ms_sgx_thread_setwait_untrusted_events_ocall_t {
|
||||
int ms_retval;
|
||||
const void* ms_waiter;
|
||||
const void* ms_self;
|
||||
} ms_sgx_thread_setwait_untrusted_events_ocall_t;
|
||||
|
||||
typedef struct ms_sgx_thread_set_multiple_untrusted_events_ocall_t {
|
||||
int ms_retval;
|
||||
const void** ms_waiters;
|
||||
size_t ms_total;
|
||||
} ms_sgx_thread_set_multiple_untrusted_events_ocall_t;
|
||||
|
||||
static sgx_status_t SGX_CDECL kbupd_enclave_kbupd_enclave_ocall_recv_enclave_msg(void* pms)
|
||||
{
|
||||
ms_kbupd_enclave_ocall_recv_enclave_msg_t* ms = SGX_CAST(ms_kbupd_enclave_ocall_recv_enclave_msg_t*, pms);
|
||||
kbupd_enclave_ocall_recv_enclave_msg(ms->ms_data, ms->ms_data_size);
|
||||
|
||||
return SGX_SUCCESS;
|
||||
}
|
||||
|
||||
static sgx_status_t SGX_CDECL kbupd_enclave_kbupd_enclave_ocall_alloc(void* pms)
|
||||
{
|
||||
ms_kbupd_enclave_ocall_alloc_t* ms = SGX_CAST(ms_kbupd_enclave_ocall_alloc_t*, pms);
|
||||
ms->ms_retval = kbupd_enclave_ocall_alloc(ms->ms_size);
|
||||
|
||||
return SGX_SUCCESS;
|
||||
}
|
||||
|
||||
static sgx_status_t SGX_CDECL kbupd_enclave_kbupd_enclave_ocall_panic(void* pms)
|
||||
{
|
||||
ms_kbupd_enclave_ocall_panic_t* ms = SGX_CAST(ms_kbupd_enclave_ocall_panic_t*, pms);
|
||||
kbupd_enclave_ocall_panic(ms->ms_msg, ms->ms_msg_size);
|
||||
|
||||
return SGX_SUCCESS;
|
||||
}
|
||||
|
||||
static sgx_status_t SGX_CDECL kbupd_enclave_sgxsd_ocall_reply(void* pms)
|
||||
{
|
||||
ms_sgxsd_ocall_reply_t* ms = SGX_CAST(ms_sgxsd_ocall_reply_t*, pms);
|
||||
ms->ms_retval = sgxsd_ocall_reply(ms->ms_reply_header, ms->ms_reply_data, ms->ms_reply_data_size, ms->ms_msg_tag);
|
||||
|
||||
return SGX_SUCCESS;
|
||||
}
|
||||
|
||||
static sgx_status_t SGX_CDECL kbupd_enclave_sgx_oc_cpuidex(void* pms)
|
||||
{
|
||||
ms_sgx_oc_cpuidex_t* ms = SGX_CAST(ms_sgx_oc_cpuidex_t*, pms);
|
||||
sgx_oc_cpuidex(ms->ms_cpuinfo, ms->ms_leaf, ms->ms_subleaf);
|
||||
|
||||
return SGX_SUCCESS;
|
||||
}
|
||||
|
||||
static sgx_status_t SGX_CDECL kbupd_enclave_sgx_thread_wait_untrusted_event_ocall(void* pms)
|
||||
{
|
||||
ms_sgx_thread_wait_untrusted_event_ocall_t* ms = SGX_CAST(ms_sgx_thread_wait_untrusted_event_ocall_t*, pms);
|
||||
ms->ms_retval = sgx_thread_wait_untrusted_event_ocall(ms->ms_self);
|
||||
|
||||
return SGX_SUCCESS;
|
||||
}
|
||||
|
||||
static sgx_status_t SGX_CDECL kbupd_enclave_sgx_thread_set_untrusted_event_ocall(void* pms)
|
||||
{
|
||||
ms_sgx_thread_set_untrusted_event_ocall_t* ms = SGX_CAST(ms_sgx_thread_set_untrusted_event_ocall_t*, pms);
|
||||
ms->ms_retval = sgx_thread_set_untrusted_event_ocall(ms->ms_waiter);
|
||||
|
||||
return SGX_SUCCESS;
|
||||
}
|
||||
|
||||
static sgx_status_t SGX_CDECL kbupd_enclave_sgx_thread_setwait_untrusted_events_ocall(void* pms)
|
||||
{
|
||||
ms_sgx_thread_setwait_untrusted_events_ocall_t* ms = SGX_CAST(ms_sgx_thread_setwait_untrusted_events_ocall_t*, pms);
|
||||
ms->ms_retval = sgx_thread_setwait_untrusted_events_ocall(ms->ms_waiter, ms->ms_self);
|
||||
|
||||
return SGX_SUCCESS;
|
||||
}
|
||||
|
||||
static sgx_status_t SGX_CDECL kbupd_enclave_sgx_thread_set_multiple_untrusted_events_ocall(void* pms)
|
||||
{
|
||||
ms_sgx_thread_set_multiple_untrusted_events_ocall_t* ms = SGX_CAST(ms_sgx_thread_set_multiple_untrusted_events_ocall_t*, pms);
|
||||
ms->ms_retval = sgx_thread_set_multiple_untrusted_events_ocall(ms->ms_waiters, ms->ms_total);
|
||||
|
||||
return SGX_SUCCESS;
|
||||
}
|
||||
|
||||
static const struct {
|
||||
size_t nr_ocall;
|
||||
void * table[9];
|
||||
} ocall_table_kbupd_enclave = {
|
||||
9,
|
||||
{
|
||||
(void*)kbupd_enclave_kbupd_enclave_ocall_recv_enclave_msg,
|
||||
(void*)kbupd_enclave_kbupd_enclave_ocall_alloc,
|
||||
(void*)kbupd_enclave_kbupd_enclave_ocall_panic,
|
||||
(void*)kbupd_enclave_sgxsd_ocall_reply,
|
||||
(void*)kbupd_enclave_sgx_oc_cpuidex,
|
||||
(void*)kbupd_enclave_sgx_thread_wait_untrusted_event_ocall,
|
||||
(void*)kbupd_enclave_sgx_thread_set_untrusted_event_ocall,
|
||||
(void*)kbupd_enclave_sgx_thread_setwait_untrusted_events_ocall,
|
||||
(void*)kbupd_enclave_sgx_thread_set_multiple_untrusted_events_ocall,
|
||||
}
|
||||
};
|
||||
sgx_status_t kbupd_enclave_recv_untrusted_msg(sgx_enclave_id_t eid, const uint8_t* data, size_t data_size)
|
||||
{
|
||||
sgx_status_t status;
|
||||
ms_kbupd_enclave_recv_untrusted_msg_t ms;
|
||||
ms.ms_data = data;
|
||||
ms.ms_data_size = data_size;
|
||||
status = sgx_ecall(eid, 0, &ocall_table_kbupd_enclave, &ms);
|
||||
return status;
|
||||
}
|
||||
|
||||
sgx_status_t sgxsd_enclave_node_init(sgx_enclave_id_t eid, sgx_status_t* retval, const sgxsd_node_init_args_t* p_args)
|
||||
{
|
||||
sgx_status_t status;
|
||||
ms_sgxsd_enclave_node_init_t ms;
|
||||
ms.ms_p_args = p_args;
|
||||
status = sgx_ecall(eid, 1, &ocall_table_kbupd_enclave, &ms);
|
||||
if (status == SGX_SUCCESS && retval) *retval = ms.ms_retval;
|
||||
return status;
|
||||
}
|
||||
|
||||
sgx_status_t sgxsd_enclave_get_next_report(sgx_enclave_id_t eid, sgx_status_t* retval, sgx_target_info_t qe_target_info, sgx_report_t* p_report)
|
||||
{
|
||||
sgx_status_t status;
|
||||
ms_sgxsd_enclave_get_next_report_t ms;
|
||||
ms.ms_qe_target_info = qe_target_info;
|
||||
ms.ms_p_report = p_report;
|
||||
status = sgx_ecall(eid, 2, &ocall_table_kbupd_enclave, &ms);
|
||||
if (status == SGX_SUCCESS && retval) *retval = ms.ms_retval;
|
||||
return status;
|
||||
}
|
||||
|
||||
sgx_status_t sgxsd_enclave_set_current_quote(sgx_enclave_id_t eid, sgx_status_t* retval)
|
||||
{
|
||||
sgx_status_t status;
|
||||
ms_sgxsd_enclave_set_current_quote_t ms;
|
||||
status = sgx_ecall(eid, 3, &ocall_table_kbupd_enclave, &ms);
|
||||
if (status == SGX_SUCCESS && retval) *retval = ms.ms_retval;
|
||||
return status;
|
||||
}
|
||||
|
||||
sgx_status_t sgxsd_enclave_negotiate_request(sgx_enclave_id_t eid, sgx_status_t* retval, const sgxsd_request_negotiation_request_t* p_request, sgxsd_request_negotiation_response_t* p_response)
|
||||
{
|
||||
sgx_status_t status;
|
||||
ms_sgxsd_enclave_negotiate_request_t ms;
|
||||
ms.ms_p_request = p_request;
|
||||
ms.ms_p_response = p_response;
|
||||
status = sgx_ecall(eid, 4, &ocall_table_kbupd_enclave, &ms);
|
||||
if (status == SGX_SUCCESS && retval) *retval = ms.ms_retval;
|
||||
return status;
|
||||
}
|
||||
|
||||
sgx_status_t sgxsd_enclave_server_start(sgx_enclave_id_t eid, sgx_status_t* retval, const sgxsd_server_init_args_t* p_args, sgxsd_server_state_handle_t state_handle)
|
||||
{
|
||||
sgx_status_t status;
|
||||
ms_sgxsd_enclave_server_start_t ms;
|
||||
ms.ms_p_args = p_args;
|
||||
ms.ms_state_handle = state_handle;
|
||||
status = sgx_ecall(eid, 5, &ocall_table_kbupd_enclave, &ms);
|
||||
if (status == SGX_SUCCESS && retval) *retval = ms.ms_retval;
|
||||
return status;
|
||||
}
|
||||
|
||||
sgx_status_t sgxsd_enclave_server_call(sgx_enclave_id_t eid, sgx_status_t* retval, const sgxsd_server_handle_call_args_t* p_args, const sgxsd_msg_header_t* msg_header, uint8_t* msg_data, size_t msg_size, sgxsd_msg_tag_t msg_tag, sgxsd_server_state_handle_t state_handle)
|
||||
{
|
||||
sgx_status_t status;
|
||||
ms_sgxsd_enclave_server_call_t ms;
|
||||
ms.ms_p_args = p_args;
|
||||
ms.ms_msg_header = msg_header;
|
||||
ms.ms_msg_data = msg_data;
|
||||
ms.ms_msg_size = msg_size;
|
||||
ms.ms_msg_tag = msg_tag;
|
||||
ms.ms_state_handle = state_handle;
|
||||
status = sgx_ecall(eid, 6, &ocall_table_kbupd_enclave, &ms);
|
||||
if (status == SGX_SUCCESS && retval) *retval = ms.ms_retval;
|
||||
return status;
|
||||
}
|
||||
|
||||
sgx_status_t sgxsd_enclave_server_stop(sgx_enclave_id_t eid, sgx_status_t* retval, const sgxsd_server_terminate_args_t* p_args, sgxsd_server_state_handle_t state_handle)
|
||||
{
|
||||
sgx_status_t status;
|
||||
ms_sgxsd_enclave_server_stop_t ms;
|
||||
ms.ms_p_args = p_args;
|
||||
ms.ms_state_handle = state_handle;
|
||||
status = sgx_ecall(eid, 7, &ocall_table_kbupd_enclave, &ms);
|
||||
if (status == SGX_SUCCESS && retval) *retval = ms.ms_retval;
|
||||
return status;
|
||||
}
|
||||
|
||||
74
enclave/include/kbupd_enclave_u.h
Normal file
74
enclave/include/kbupd_enclave_u.h
Normal file
@ -0,0 +1,74 @@
|
||||
#ifndef KBUPD_ENCLAVE_U_H__
|
||||
#define KBUPD_ENCLAVE_U_H__
|
||||
|
||||
#include <stdint.h>
|
||||
#include <wchar.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "sgx_edger8r.h" /* for sgx_status_t etc. */
|
||||
|
||||
#include "kbupd_sgxsd_callbacks.h"
|
||||
#include "stdbool.h"
|
||||
#include "sgx_quote.h"
|
||||
#include "sgx_report.h"
|
||||
#include "sgxsd.h"
|
||||
|
||||
#include <stdlib.h> /* for size_t */
|
||||
|
||||
#define SGX_CAST(type, item) ((type)(item))
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef KBUPD_ENCLAVE_OCALL_RECV_ENCLAVE_MSG_DEFINED__
|
||||
#define KBUPD_ENCLAVE_OCALL_RECV_ENCLAVE_MSG_DEFINED__
|
||||
void SGX_UBRIDGE(SGX_NOCONVENTION, kbupd_enclave_ocall_recv_enclave_msg, (const uint8_t* data, size_t data_size));
|
||||
#endif
|
||||
#ifndef KBUPD_ENCLAVE_OCALL_ALLOC_DEFINED__
|
||||
#define KBUPD_ENCLAVE_OCALL_ALLOC_DEFINED__
|
||||
void* SGX_UBRIDGE(SGX_NOCONVENTION, kbupd_enclave_ocall_alloc, (size_t* size));
|
||||
#endif
|
||||
#ifndef KBUPD_ENCLAVE_OCALL_PANIC_DEFINED__
|
||||
#define KBUPD_ENCLAVE_OCALL_PANIC_DEFINED__
|
||||
void SGX_UBRIDGE(SGX_NOCONVENTION, kbupd_enclave_ocall_panic, (const uint8_t* msg, size_t msg_size));
|
||||
#endif
|
||||
#ifndef SGXSD_OCALL_REPLY_DEFINED__
|
||||
#define SGXSD_OCALL_REPLY_DEFINED__
|
||||
sgx_status_t SGX_UBRIDGE(SGX_NOCONVENTION, sgxsd_ocall_reply, (const sgxsd_msg_header_t* reply_header, const uint8_t* reply_data, size_t reply_data_size, sgxsd_msg_tag_t msg_tag));
|
||||
#endif
|
||||
#ifndef SGX_OC_CPUIDEX_DEFINED__
|
||||
#define SGX_OC_CPUIDEX_DEFINED__
|
||||
void SGX_UBRIDGE(SGX_CDECL, sgx_oc_cpuidex, (int cpuinfo[4], int leaf, int subleaf));
|
||||
#endif
|
||||
#ifndef SGX_THREAD_WAIT_UNTRUSTED_EVENT_OCALL_DEFINED__
|
||||
#define SGX_THREAD_WAIT_UNTRUSTED_EVENT_OCALL_DEFINED__
|
||||
int SGX_UBRIDGE(SGX_CDECL, sgx_thread_wait_untrusted_event_ocall, (const void* self));
|
||||
#endif
|
||||
#ifndef SGX_THREAD_SET_UNTRUSTED_EVENT_OCALL_DEFINED__
|
||||
#define SGX_THREAD_SET_UNTRUSTED_EVENT_OCALL_DEFINED__
|
||||
int SGX_UBRIDGE(SGX_CDECL, sgx_thread_set_untrusted_event_ocall, (const void* waiter));
|
||||
#endif
|
||||
#ifndef SGX_THREAD_SETWAIT_UNTRUSTED_EVENTS_OCALL_DEFINED__
|
||||
#define SGX_THREAD_SETWAIT_UNTRUSTED_EVENTS_OCALL_DEFINED__
|
||||
int SGX_UBRIDGE(SGX_CDECL, sgx_thread_setwait_untrusted_events_ocall, (const void* waiter, const void* self));
|
||||
#endif
|
||||
#ifndef SGX_THREAD_SET_MULTIPLE_UNTRUSTED_EVENTS_OCALL_DEFINED__
|
||||
#define SGX_THREAD_SET_MULTIPLE_UNTRUSTED_EVENTS_OCALL_DEFINED__
|
||||
int SGX_UBRIDGE(SGX_CDECL, sgx_thread_set_multiple_untrusted_events_ocall, (const void** waiters, size_t total));
|
||||
#endif
|
||||
|
||||
sgx_status_t kbupd_enclave_recv_untrusted_msg(sgx_enclave_id_t eid, const uint8_t* data, size_t data_size);
|
||||
sgx_status_t sgxsd_enclave_node_init(sgx_enclave_id_t eid, sgx_status_t* retval, const sgxsd_node_init_args_t* p_args);
|
||||
sgx_status_t sgxsd_enclave_get_next_report(sgx_enclave_id_t eid, sgx_status_t* retval, sgx_target_info_t qe_target_info, sgx_report_t* p_report);
|
||||
sgx_status_t sgxsd_enclave_set_current_quote(sgx_enclave_id_t eid, sgx_status_t* retval);
|
||||
sgx_status_t sgxsd_enclave_negotiate_request(sgx_enclave_id_t eid, sgx_status_t* retval, const sgxsd_request_negotiation_request_t* p_request, sgxsd_request_negotiation_response_t* p_response);
|
||||
sgx_status_t sgxsd_enclave_server_start(sgx_enclave_id_t eid, sgx_status_t* retval, const sgxsd_server_init_args_t* p_args, sgxsd_server_state_handle_t state_handle);
|
||||
sgx_status_t sgxsd_enclave_server_call(sgx_enclave_id_t eid, sgx_status_t* retval, const sgxsd_server_handle_call_args_t* p_args, const sgxsd_msg_header_t* msg_header, uint8_t* msg_data, size_t msg_size, sgxsd_msg_tag_t msg_tag, sgxsd_server_state_handle_t state_handle);
|
||||
sgx_status_t sgxsd_enclave_server_stop(sgx_enclave_id_t eid, sgx_status_t* retval, const sgxsd_server_terminate_args_t* p_args, sgxsd_server_state_handle_t state_handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif
|
||||
31
enclave/include/kbupd_sgxsd_callbacks.h
Normal file
31
enclave/include/kbupd_sgxsd_callbacks.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef _KBUPD_SGXSD_CALLBACKS_H
|
||||
#define _KBUPD_SGXSD_CALLBACKS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef enum kbupd_request_type {
|
||||
KBUPD_REQUEST_TYPE_ANY = 0,
|
||||
KBUPD_REQUEST_TYPE_BACKUP = 1,
|
||||
KBUPD_REQUEST_TYPE_RESTORE = 2,
|
||||
KBUPD_REQUEST_TYPE_DELETE = 3,
|
||||
} kbupd_request_type_t;
|
||||
|
||||
typedef struct sgxsd_server_init_args {
|
||||
} sgxsd_server_init_args_t;
|
||||
_Static_assert(sizeof(sgxsd_server_init_args_t) == 0, "Enclave ABI compatibility");
|
||||
|
||||
typedef struct sgxsd_server_handle_call_args {
|
||||
uint8_t backup_id[32];
|
||||
uint32_t request_type;
|
||||
} sgxsd_server_handle_call_args_t;
|
||||
_Static_assert(sizeof(sgxsd_server_handle_call_args_t) == 36, "Enclave ABI compatibility");
|
||||
|
||||
typedef struct sgxsd_server_terminate_args {
|
||||
} sgxsd_server_terminate_args_t;
|
||||
_Static_assert(sizeof(sgxsd_server_terminate_args_t) == 0, "Enclave ABI compatibility");
|
||||
|
||||
typedef struct sgxsd_ra_get_quote_args {
|
||||
const void *args;
|
||||
} sgxsd_ra_get_quote_args_t;
|
||||
|
||||
#endif
|
||||
97
enclave/include/sgxsd-enclave.h
Normal file
97
enclave/include/sgxsd-enclave.h
Normal file
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Jeff Griffin
|
||||
*/
|
||||
#ifndef _SGXSD_ENCLAVE_H
|
||||
#define _SGXSD_ENCLAVE_H
|
||||
|
||||
#include "sgx_error.h"
|
||||
|
||||
#include "sgxsd.h"
|
||||
|
||||
typedef struct sgxsd_msg_buf {
|
||||
uint8_t *data;
|
||||
uint32_t size;
|
||||
} sgxsd_msg_buf_t;
|
||||
|
||||
typedef struct sgxsd_msg_from {
|
||||
bool valid;
|
||||
sgxsd_msg_tag_t tag;
|
||||
sgxsd_aes_gcm_key_t server_key;
|
||||
} sgxsd_msg_from_t;
|
||||
|
||||
//
|
||||
// callbacks
|
||||
//
|
||||
|
||||
// the incomplete type sgxsd_server_state doesn't necessarily need to be defined
|
||||
typedef struct sgxsd_server_state sgxsd_server_state_t;
|
||||
|
||||
/* the incomplete types sgxsd_server_{init,handle_call,terminate}_args must be defined and included before sgxsd APIs
|
||||
in the .edl file */
|
||||
typedef struct sgxsd_server_init_args sgxsd_server_init_args_t;
|
||||
typedef struct sgxsd_server_handle_call_args sgxsd_server_handle_call_args_t;
|
||||
typedef struct sgxsd_server_terminate_args sgxsd_server_terminate_args_t;
|
||||
|
||||
// the callbacks sgxsd_enclave_server_{init,handle_call,terminate} handle sgxsd_enclave_server_{start,call,stop} calls
|
||||
sgx_status_t sgxsd_enclave_server_init(const sgxsd_server_init_args_t *p_args, sgxsd_server_state_t **pp_state);
|
||||
sgx_status_t sgxsd_enclave_server_handle_call(const sgxsd_server_handle_call_args_t *p_args, sgxsd_msg_buf_t msg, sgxsd_msg_from_t from, sgxsd_server_state_t **pp_state);
|
||||
sgx_status_t sgxsd_enclave_server_terminate(const sgxsd_server_terminate_args_t *p_args, sgxsd_server_state_t *p_state);
|
||||
|
||||
//
|
||||
// public api
|
||||
//
|
||||
|
||||
// sgxsd_enclave_server_reply sends a reply to the message corresponding to the given sgxsd_msg_from from handle_call
|
||||
sgx_status_t sgxsd_enclave_server_reply(sgxsd_msg_buf_t reply_buf, sgxsd_msg_from_t *p_from);
|
||||
|
||||
sgx_status_t sgxsd_enclave_server_noreply(sgxsd_msg_from_t *p_from);
|
||||
|
||||
//
|
||||
// public utility apis
|
||||
//
|
||||
|
||||
sgx_status_t sgxsd_aes_gcm_encrypt(const sgxsd_aes_gcm_key_t *p_key,
|
||||
const void *p_src, uint32_t src_len, void *p_dst,
|
||||
const sgxsd_aes_gcm_iv_t *p_iv,
|
||||
const void *p_aad, uint32_t aad_len,
|
||||
sgxsd_aes_gcm_mac_t *p_out_mac);
|
||||
|
||||
sgx_status_t sgxsd_aes_gcm_decrypt(const sgxsd_aes_gcm_key_t *p_key,
|
||||
const void *p_src, uint32_t src_len, void *p_dst,
|
||||
const sgxsd_aes_gcm_iv_t *p_iv,
|
||||
const void *p_aad, uint32_t aad_len,
|
||||
const sgxsd_aes_gcm_mac_t *p_in_mac);
|
||||
|
||||
typedef struct sgxsd_rand_buf {
|
||||
uint8_t x[SGXSD_CURVE25519_KEY_SIZE];
|
||||
} sgxsd_rand_buf_t, sgxsd_curve25519_private_key_t;
|
||||
|
||||
sgx_status_t sgxsd_enclave_read_rand(sgxsd_rand_buf_t *p_privkey);
|
||||
|
||||
//
|
||||
// internal definitions
|
||||
//
|
||||
|
||||
typedef struct sgxsd_curve25519_key_pair {
|
||||
sgxsd_curve25519_private_key_t privkey;
|
||||
sgxsd_curve25519_public_key_t pubkey;
|
||||
} sgxsd_curve25519_key_pair_t;
|
||||
|
||||
#endif
|
||||
36
enclave/include/sgxsd.edl
Normal file
36
enclave/include/sgxsd.edl
Normal file
@ -0,0 +1,36 @@
|
||||
enclave {
|
||||
include "stdbool.h"
|
||||
include "sgx_quote.h"
|
||||
include "sgx_report.h"
|
||||
include "sgxsd.h"
|
||||
|
||||
trusted {
|
||||
public sgx_status_t sgxsd_enclave_node_init([in] const sgxsd_node_init_args_t *p_args);
|
||||
|
||||
public sgx_status_t sgxsd_enclave_get_next_report
|
||||
(sgx_target_info_t qe_target_info, [out] sgx_report_t *p_report);
|
||||
public sgx_status_t sgxsd_enclave_set_current_quote();
|
||||
|
||||
public sgx_status_t sgxsd_enclave_negotiate_request
|
||||
([in] const sgxsd_request_negotiation_request_t *p_request,
|
||||
[out] sgxsd_request_negotiation_response_t *p_response);
|
||||
|
||||
public sgx_status_t sgxsd_enclave_server_start
|
||||
([in] const sgxsd_server_init_args_t *p_args,
|
||||
sgxsd_server_state_handle_t state_handle);
|
||||
public sgx_status_t sgxsd_enclave_server_call
|
||||
([in] const sgxsd_server_handle_call_args_t *p_args,
|
||||
[in] const sgxsd_msg_header_t *msg_header,
|
||||
[in, size=msg_size] uint8_t *msg_data, size_t msg_size,
|
||||
sgxsd_msg_tag_t msg_tag, sgxsd_server_state_handle_t state_handle);
|
||||
public sgx_status_t sgxsd_enclave_server_stop
|
||||
([in] const sgxsd_server_terminate_args_t *p_args,
|
||||
sgxsd_server_state_handle_t state_handle);
|
||||
};
|
||||
untrusted {
|
||||
sgx_status_t sgxsd_ocall_reply
|
||||
([in] const sgxsd_msg_header_t *reply_header,
|
||||
[in, size=reply_data_size] const uint8_t *reply_data, size_t reply_data_size,
|
||||
sgxsd_msg_tag_t msg_tag);
|
||||
};
|
||||
};
|
||||
139
enclave/include/sgxsd.h
Normal file
139
enclave/include/sgxsd.h
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2017 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Jeff Griffin
|
||||
*/
|
||||
#ifndef _SGXSD_H
|
||||
#define _SGXSD_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "sgx_urts.h"
|
||||
#include "sgx_quote.h"
|
||||
|
||||
//
|
||||
// types
|
||||
//
|
||||
|
||||
#define SGXSD_AES_GCM_IV_SIZE 12
|
||||
#define SGXSD_AES_GCM_MAC_SIZE 16
|
||||
#define SGXSD_AES_GCM_KEY_SIZE 32
|
||||
#define SGXSD_CURVE25519_KEY_SIZE 32
|
||||
#define SGXSD_SHA256_HASH_SIZE 32
|
||||
|
||||
typedef struct sgxsd_aes_gcm_mac {
|
||||
uint8_t data[SGXSD_AES_GCM_MAC_SIZE];
|
||||
} sgxsd_aes_gcm_mac_t;
|
||||
_Static_assert(sizeof(sgxsd_aes_gcm_mac_t) == SGXSD_AES_GCM_MAC_SIZE, "Enclave ABI compatibility");
|
||||
|
||||
typedef struct sgxsd_aes_gcm_iv {
|
||||
uint8_t data[SGXSD_AES_GCM_IV_SIZE];
|
||||
} sgxsd_aes_gcm_iv_t;
|
||||
_Static_assert(sizeof(sgxsd_aes_gcm_iv_t) == SGXSD_AES_GCM_IV_SIZE, "Enclave ABI compatibility");
|
||||
|
||||
typedef struct sgxsd_aes_gcm_key {
|
||||
uint8_t data[SGXSD_AES_GCM_KEY_SIZE];
|
||||
} sgxsd_aes_gcm_key_t;
|
||||
_Static_assert(sizeof(sgxsd_aes_gcm_key_t) == SGXSD_AES_GCM_KEY_SIZE, "Enclave ABI compatibility");
|
||||
|
||||
typedef struct sgxsd_curve25519_public_key {
|
||||
uint8_t x[SGXSD_CURVE25519_KEY_SIZE];
|
||||
} sgxsd_curve25519_public_key_t;
|
||||
_Static_assert(sizeof(sgxsd_curve25519_public_key_t) == SGXSD_CURVE25519_KEY_SIZE, "Enclave ABI compatibility");
|
||||
|
||||
typedef struct sgxsd_request_negotiation_request {
|
||||
sgxsd_curve25519_public_key_t client_pubkey;
|
||||
} sgxsd_request_negotiation_request_t;
|
||||
_Static_assert(sizeof(sgxsd_request_negotiation_request_t) == sizeof(sgxsd_curve25519_public_key_t), "Enclave ABI compatibility");
|
||||
|
||||
typedef struct sgxsd_pending_request_id {
|
||||
uint8_t data[sizeof(uint64_t)];
|
||||
sgxsd_aes_gcm_iv_t iv;
|
||||
sgxsd_aes_gcm_mac_t mac;
|
||||
} sgxsd_pending_request_id_t;
|
||||
_Static_assert(sizeof(sgxsd_pending_request_id_t) == sizeof(uint64_t) + sizeof(sgxsd_aes_gcm_iv_t) + sizeof(sgxsd_aes_gcm_mac_t), "Enclave ABI compatibility");
|
||||
|
||||
typedef struct sgxsd_request_negotiation_response {
|
||||
sgxsd_curve25519_public_key_t server_static_pubkey;
|
||||
sgxsd_curve25519_public_key_t server_ephemeral_pubkey;
|
||||
struct {
|
||||
uint8_t data[sizeof(sgxsd_pending_request_id_t)];
|
||||
sgxsd_aes_gcm_iv_t iv;
|
||||
sgxsd_aes_gcm_mac_t mac;
|
||||
} encrypted_pending_request_id;
|
||||
} sgxsd_request_negotiation_response_t;
|
||||
_Static_assert(sizeof(sgxsd_request_negotiation_response_t) == sizeof(sgxsd_curve25519_public_key_t) * 2 + sizeof(sgxsd_pending_request_id_t) + sizeof(sgxsd_aes_gcm_iv_t) + sizeof(sgxsd_aes_gcm_mac_t), "Enclave ABI compatibility");
|
||||
|
||||
typedef struct sgxsd_msg_tag {
|
||||
union {
|
||||
void *p_tag;
|
||||
uint64_t tag;
|
||||
};
|
||||
} sgxsd_msg_tag_t;
|
||||
_Static_assert(sizeof(sgxsd_msg_tag_t) == sizeof(uint64_t), "Enclave ABI compatibility");
|
||||
|
||||
typedef struct sgxsd_msg_header {
|
||||
sgxsd_aes_gcm_iv_t iv;
|
||||
sgxsd_aes_gcm_mac_t mac;
|
||||
sgxsd_pending_request_id_t pending_request_id;
|
||||
} sgxsd_msg_header_t;
|
||||
_Static_assert(sizeof(sgxsd_msg_header_t) == sizeof(sgxsd_aes_gcm_iv_t) + sizeof(sgxsd_aes_gcm_mac_t) + sizeof(sgxsd_pending_request_id_t), "Enclave ABI compatibility");
|
||||
|
||||
typedef struct sgxsd_node_init_args {
|
||||
uint8_t pending_requests_table_order;
|
||||
} sgxsd_node_init_args_t;
|
||||
|
||||
typedef uint64_t sgxsd_server_state_handle_t;
|
||||
|
||||
//
|
||||
// public api (untrusted)
|
||||
//
|
||||
|
||||
#define sgxsd_status_ok() (sgxsd_status_t) { .ok = true, .name = "ok", .code = 0 }
|
||||
#define sgxsd_status_error(Name) (sgxsd_status_t) { .ok = false, .name = Name, .code = 0 }
|
||||
#define sgxsd_status_error_code(Name, SgxStatus) (sgxsd_status_t) { .ok = false, .name = Name, .code = SgxStatus }
|
||||
typedef struct sgxsd_status {
|
||||
bool ok;
|
||||
const char *name;
|
||||
int64_t code;
|
||||
} sgxsd_status_t;
|
||||
|
||||
typedef struct sgxsd_enclave {
|
||||
sgx_enclave_id_t id;
|
||||
union {
|
||||
sgx_epid_group_id_t gid;
|
||||
uint32_t gid32;
|
||||
};
|
||||
sgx_launch_token_t launch_token;
|
||||
} sgxsd_enclave_t;
|
||||
|
||||
typedef sgxsd_status_t (*sgxsd_start_callback_t)(sgxsd_enclave_t, va_list);
|
||||
sgxsd_status_t sgxsd_start(const char *enclave_path, bool debug, const sgx_launch_token_t *p_launch_token, const sgxsd_node_init_args_t *p_node_init_args, sgxsd_start_callback_t p_callback, ...);
|
||||
sgxsd_status_t sgxsd_get_next_quote(sgx_enclave_id_t enclave_id, sgx_spid_t spid, const uint8_t *p_sig_rl, uint32_t sig_rl_size, sgx_quote_t *p_quote, uint32_t quote_size);
|
||||
|
||||
//
|
||||
// error codes
|
||||
//
|
||||
|
||||
typedef enum sgxsd_status_code {
|
||||
SGXSD_ERROR_PENDING_REQUEST_NOT_FOUND = SGX_MK_ERROR(0x10001),
|
||||
} sgxsd_status_code_t;
|
||||
|
||||
#endif
|
||||
58
enclave/include/test_memset_s.h
Normal file
58
enclave/include/test_memset_s.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef TEST_MEMSET_S_H__
|
||||
#define TEST_MEMSET_S_H__
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
static void *(* const volatile __memset_vp)(void *, int, size_t) = memset;
|
||||
static inline
|
||||
int memset_s(void *s, size_t smax, int c, size_t n) {
|
||||
int err = 0;
|
||||
|
||||
if (s == NULL) {
|
||||
errno = err = EINVAL;
|
||||
return err;
|
||||
}
|
||||
if (smax > SIZE_MAX) {
|
||||
errno = err = E2BIG;
|
||||
return err;
|
||||
}
|
||||
if (n > SIZE_MAX) {
|
||||
err = E2BIG;
|
||||
n = smax;
|
||||
}
|
||||
if (n > smax) {
|
||||
err = EOVERFLOW;
|
||||
n = smax;
|
||||
}
|
||||
|
||||
(*__memset_vp)(s, c, n);
|
||||
|
||||
if (err == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
errno = err;
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
2
enclave/kbupd_enclave/.cargo/config
Normal file
2
enclave/kbupd_enclave/.cargo/config
Normal file
@ -0,0 +1,2 @@
|
||||
[build]
|
||||
target-dir = "../build/target"
|
||||
44
enclave/kbupd_enclave/Cargo.toml
Normal file
44
enclave/kbupd_enclave/Cargo.toml
Normal file
@ -0,0 +1,44 @@
|
||||
[package]
|
||||
authors = ["Open Whisper Systems"]
|
||||
name = "kbupd_enclave"
|
||||
version = "0.1.0"
|
||||
license = "AGPL-3.0-or-later"
|
||||
edition = "2018"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
insecure = []
|
||||
debug = ["insecure"]
|
||||
trace = ["debug", "insecure"]
|
||||
test = ["sgx_ffi/test", "sgxsd_ffi/test"]
|
||||
|
||||
[dependencies]
|
||||
base64 = { rev = "07b1d6b713cc2bd7d107185bd0d14bf06cddfb48", git = "https://github.com/marshallpierce/rust-base64.git", default-features = false, features = ["alloc"] }
|
||||
bytes = { rev = "ebe96021b0eaf52be1fedd0a925f4384275c9cc4", git = "https://github.com/tokio-rs/bytes.git", default-features = false, features = [] }
|
||||
chrono = { rev = "de22e82a1b00b8f015a1d736e497c3177e8e8c9f", git = "https://github.com/geogriff-signal/chrono.git", default-features = false, features = [] }
|
||||
hashbrown = { version = "0.6", default-features = false, features = [] }
|
||||
intrusive-collections = { rev = "3c14ea97598616a2beaa97cd5fbbb27ba574fe77", git = "https://github.com/geogriff-signal/intrusive-rs.git" }
|
||||
lazy_static = { version = "1.4", features = ["spin_no_std"] }
|
||||
libc = { version = "0.2", default-features = false, features = [] }
|
||||
no-std-compat = { version = "0.2", features = ["alloc"] }
|
||||
num-traits = { version = "0.2", default-features = false, features = [] }
|
||||
prost = { rev = "907f7d6e714d0b449d75269d532561c71d3ed250", git = "https://github.com/geogriff-signal/prost.git", default-features = false, features = ["prost-derive"] }
|
||||
rand_core = { version = "0.5", default-features = false, features = [] }
|
||||
serde = { version = "1.0", default-features = false, features = ["derive", "alloc"] }
|
||||
serde_json = { rev = "d79b0c67f62e168d4872bb8694377ffd97b8949f", git = "https://github.com/geogriff-signal/serde_json.git", default-features = false, features = [] }
|
||||
sgx_ffi = { path = "../sgx_ffi" }
|
||||
sgxsd_ffi = { path = "../sgxsd_ffi" }
|
||||
spin = "0.5"
|
||||
snow = { rev = "d8d00a37c8e39b2557d23a26cc4f722595b4f2d9", git = "https://github.com/geogriff-signal/snow.git", default-features = false, features = [] }
|
||||
webpki = { rev = "32ab63c46edfbfe9c1fe68008ba8e247eb387ca3", git = "https://github.com/geogriff-signal/webpki.git", default-features = false, features = [] }
|
||||
|
||||
[dev-dependencies]
|
||||
lazy_static = "1.4"
|
||||
mockers = "0.21"
|
||||
mockers_derive = "0.21"
|
||||
rand = { version = "0.7", default-features = false, features = [] }
|
||||
rand_chacha = { version = "0.2", default-features = false, features = [] }
|
||||
test_ffi = { path = "../test_ffi" }
|
||||
|
||||
[lib]
|
||||
crate-type = ["staticlib"]
|
||||
1
enclave/kbupd_enclave/lsan-ignore-test.txt
Normal file
1
enclave/kbupd_enclave/lsan-ignore-test.txt
Normal file
@ -0,0 +1 @@
|
||||
leak:backtrace_alloc
|
||||
81
enclave/kbupd_enclave/src/allocator.rs
Normal file
81
enclave/kbupd_enclave/src/allocator.rs
Normal file
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
use alloc::alloc::*;
|
||||
use core::cmp;
|
||||
use core::ptr;
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
const MIN_ALIGN: usize = 8;
|
||||
|
||||
pub struct System;
|
||||
unsafe impl GlobalAlloc for System {
|
||||
#[inline]
|
||||
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
||||
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
|
||||
libc::malloc(layout.size()) as *mut u8
|
||||
} else {
|
||||
libc::memalign(layout.align(), layout.size()) as *mut u8
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
|
||||
if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
|
||||
libc::calloc(layout.size(), 1) as *mut u8
|
||||
} else {
|
||||
let ptr = self.alloc(layout.clone());
|
||||
if !ptr.is_null() {
|
||||
ptr::write_bytes(ptr, 0, layout.size());
|
||||
}
|
||||
ptr
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, _layout: Layout) {
|
||||
libc::free(ptr as *mut libc::c_void)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
|
||||
if layout.align() <= MIN_ALIGN && layout.align() <= new_size {
|
||||
libc::realloc(ptr as *mut libc::c_void, new_size) as *mut u8
|
||||
} else {
|
||||
realloc_fallback(self, ptr, layout, new_size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn realloc_fallback(alloc: &System, ptr: *mut u8, old_layout: Layout, new_size: usize) -> *mut u8 {
|
||||
let new_layout = Layout::from_size_align_unchecked(new_size, old_layout.align());
|
||||
|
||||
let new_ptr = GlobalAlloc::alloc(alloc, new_layout);
|
||||
if !new_ptr.is_null() {
|
||||
let size = cmp::min(old_layout.size(), new_size);
|
||||
ptr::copy_nonoverlapping(ptr, new_ptr, size);
|
||||
GlobalAlloc::dealloc(alloc, ptr, old_layout);
|
||||
}
|
||||
new_ptr
|
||||
}
|
||||
|
||||
#[alloc_error_handler]
|
||||
pub fn handle_alloc_error(layout: Layout) -> ! {
|
||||
let status = sgx_ffi::util::MemoryStatus::collect();
|
||||
panic!("out of memory allocating {} bytes with {} used of {} bytes in {} chunks",
|
||||
layout.size(), status.used_bytes, status.footprint_bytes, status.free_chunks);
|
||||
}
|
||||
19
enclave/kbupd_enclave/src/ffi/bindgen_wrapper.h
Normal file
19
enclave/kbupd_enclave/src/ffi/bindgen_wrapper.h
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include "kbupd_sgxsd_callbacks.h"
|
||||
#include "kbupd_enclave_t.h"
|
||||
2844
enclave/kbupd_enclave/src/ffi/bindgen_wrapper.rs
Normal file
2844
enclave/kbupd_enclave/src/ffi/bindgen_wrapper.rs
Normal file
File diff suppressed because it is too large
Load Diff
235
enclave/kbupd_enclave/src/ffi/ecalls.rs
Normal file
235
enclave/kbupd_enclave/src/ffi/ecalls.rs
Normal file
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
use std::cell::*;
|
||||
use std::ptr::{NonNull};
|
||||
use std::slice;
|
||||
|
||||
use prost::Message;
|
||||
use sgx_ffi::untrusted_slice::{UntrustedSlice};
|
||||
|
||||
pub use super::bindgen_wrapper::{
|
||||
sgxsd_server_init_args_t as StartArgs,
|
||||
sgxsd_server_handle_call_args_t as CallArgs,
|
||||
sgxsd_server_terminate_args_t as StopArgs,
|
||||
KBUPD_REQUEST_TYPE_ANY,
|
||||
KBUPD_REQUEST_TYPE_BACKUP,
|
||||
KBUPD_REQUEST_TYPE_RESTORE,
|
||||
KBUPD_REQUEST_TYPE_DELETE,
|
||||
};
|
||||
use super::bindgen_wrapper::{
|
||||
kbupd_enclave_ocall_recv_enclave_msg,
|
||||
kbupd_enclave_ocall_alloc,
|
||||
};
|
||||
|
||||
use crate::protobufs::kbupd::{UntrustedMessageBatch, UntrustedMessage, EnclaveMessageBatch, EnclaveMessage};
|
||||
|
||||
pub trait KbupdService {
|
||||
fn untrusted_message(&mut self, message: UntrustedMessage);
|
||||
}
|
||||
|
||||
const ENCLAVE_MESSAGE_BUFFER_SIZE: usize = 10240;
|
||||
|
||||
#[cfg(not(any(test, feature = "test")))]
|
||||
pub fn with_buffer<F, R>(fun: F) -> R
|
||||
where F: FnOnce(&RefCell<Option<Vec<u8>>>) -> R
|
||||
{
|
||||
#[thread_local]
|
||||
static ENCLAVE_MESSAGE_BUFFER: RefCell<Option<Vec<u8>>> = RefCell::new(None);
|
||||
|
||||
fun(&ENCLAVE_MESSAGE_BUFFER)
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test"))]
|
||||
pub fn with_buffer<F, R>(fun: F) -> R
|
||||
where F: FnOnce(&RefCell<Option<Vec<u8>>>) -> R
|
||||
{
|
||||
thread_local! {
|
||||
static ENCLAVE_MESSAGE_BUFFER: RefCell<Option<Vec<u8>>> = RefCell::new(None);
|
||||
}
|
||||
ENCLAVE_MESSAGE_BUFFER.with(fun)
|
||||
}
|
||||
|
||||
pub fn kbupd_enclave_alloc_untrusted(mut size: usize) -> Result<UntrustedSlice<'static>, ()> {
|
||||
let mut p_data: *mut libc::c_void = std::ptr::null_mut();
|
||||
match unsafe { kbupd_enclave_ocall_alloc(&mut p_data, &mut size) } {
|
||||
0 => UntrustedSlice::new(p_data as *mut u8, size),
|
||||
error => {
|
||||
error!("ocall error allocating {} bytes from untrusted: {}", size, error);
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kbupd_enclave_recv_untrusted_msg<S>(service: &mut S, p_data: *const u8, data_size: usize)
|
||||
where S: KbupdService,
|
||||
{
|
||||
let data = ECallSlice(NonNull::new(p_data as *mut _), data_size);
|
||||
|
||||
match UntrustedMessageBatch::decode(data.as_ref()) {
|
||||
Ok(batch) => {
|
||||
for message in batch.messages {
|
||||
service.untrusted_message(message);
|
||||
}
|
||||
}
|
||||
Err(decode_error) => {
|
||||
error!("error decoding untrusted messages: {}", decode_error);
|
||||
}
|
||||
}
|
||||
kbupd_send_flush();
|
||||
}
|
||||
|
||||
pub fn kbupd_send(message: EnclaveMessage) {
|
||||
let batch = EnclaveMessageBatch { messages: vec![message] };
|
||||
let buffer_len = with_buffer(|buffer| buffer.borrow().as_ref().map(Vec::len).unwrap_or(0));
|
||||
if buffer_len.saturating_add(batch.encoded_len()) > ENCLAVE_MESSAGE_BUFFER_SIZE {
|
||||
kbupd_send_flush();
|
||||
}
|
||||
with_buffer(|buffer| {
|
||||
let mut buffer_ref_mut = RefMut::map(buffer.borrow_mut(), |maybe_buffer: &mut Option<Vec<u8>>| {
|
||||
maybe_buffer.get_or_insert_with(|| Vec::with_capacity(ENCLAVE_MESSAGE_BUFFER_SIZE))
|
||||
});
|
||||
let buffer_mut: &mut Vec<u8> = buffer_ref_mut.as_mut();
|
||||
assert!(batch.encode(buffer_mut).is_ok());
|
||||
});
|
||||
}
|
||||
|
||||
pub fn kbupd_send_flush() {
|
||||
let maybe_buffer = with_buffer(|buffer_tls| {
|
||||
std::mem::replace(&mut *buffer_tls.borrow_mut(), Default::default())
|
||||
});
|
||||
let mut buffer = match maybe_buffer {
|
||||
Some(buffer) => buffer,
|
||||
None => return,
|
||||
};
|
||||
if !buffer.is_empty() {
|
||||
let ocall_res = unsafe { kbupd_enclave_ocall_recv_enclave_msg(buffer.as_ptr(), buffer.len()) };
|
||||
assert_eq!(ocall_res, 0);
|
||||
}
|
||||
buffer.truncate(0);
|
||||
|
||||
with_buffer(|buffer_tls| {
|
||||
if buffer_tls.borrow().as_ref().map(Vec::is_empty).unwrap_or(true) {
|
||||
if buffer.capacity() == ENCLAVE_MESSAGE_BUFFER_SIZE {
|
||||
*buffer_tls.borrow_mut() = Some(buffer);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
struct ECallSlice(Option<NonNull<u8>>, usize);
|
||||
impl AsRef<[u8]> for ECallSlice {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
if self.1 != 0 {
|
||||
if let Some(ptr) = self.0 {
|
||||
unsafe { slice::from_raw_parts(ptr.as_ptr(), self.1) }
|
||||
} else {
|
||||
&[]
|
||||
}
|
||||
} else {
|
||||
&[]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use super::super::mocks;
|
||||
use mockers::*;
|
||||
|
||||
struct MockKbupdService {}
|
||||
impl KbupdService for MockKbupdService {
|
||||
fn untrusted_message(&mut self, _message: UntrustedMessage) {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kbupd_enclave_recv_untrusted_msg_empty() {
|
||||
let mut kbupd_service = MockKbupdService {};
|
||||
kbupd_enclave_recv_untrusted_msg(&mut kbupd_service, std::ptr::null(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kbupd_enclave_recv_untrusted_msg_bad() {
|
||||
let bad_requests: &[&[u8]] = &[
|
||||
// bad tag 0, types 0..=7, truncated
|
||||
&[0x00], &[0x01], &[0x02], &[0x03], &[0x04], &[0x05], &[0x06], &[0x07],
|
||||
// tag 1, bad types 0..=1, truncated
|
||||
&[0x08], &[0x09],
|
||||
// tag 1, type 2, truncated
|
||||
&[0x0A],
|
||||
// tag 1, bad types 3..=7, truncated
|
||||
&[0x0B], &[0x0C], &[0x0D], &[0x0E], &[0x0F],
|
||||
// tag 2, types 0..=7, truncated
|
||||
&[0x10], &[0x11], &[0x12], &[0x13], &[0x14], &[0x15], &[0x16], &[0x17],
|
||||
|
||||
// tag 1, bad type 0
|
||||
&[0x08, 0x00],
|
||||
// tag 1, type 2, length 1, truncated
|
||||
&[0x0A, 0x01],
|
||||
// tag 1, type 2, length 2^64-1, truncated
|
||||
&[0x0A, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01],
|
||||
// tag 1, type 2, length 1 (overlong varint), truncated
|
||||
&[0x0A, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00],
|
||||
&[0x0A, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x02],
|
||||
|
||||
// tag 2, type 0, bad varints
|
||||
&[0x10, 0x80],
|
||||
&[0x10, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80],
|
||||
&[0x10, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00],
|
||||
|
||||
// bad tag 0 (overlong varint), type 0
|
||||
&[0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
|
||||
&[0x80, 0x80, 0x80, 0x00, 0x00],
|
||||
|
||||
// bad tag 2^32, type 0
|
||||
&[0x80, 0x80, 0x80, 0x80, 0x10, 0x00],
|
||||
// bad tag 2^64-1, type 0
|
||||
&[0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00],
|
||||
// bad tag (bad varint)
|
||||
&[0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80],
|
||||
&[0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00],
|
||||
];
|
||||
let null_requests: &[&[u8]] = &[
|
||||
// empty
|
||||
&[],
|
||||
|
||||
// tag 1, type 2, length 0 (overlong varint)
|
||||
&[0x0A, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00],
|
||||
// tag 1, type 2, length 0 (overlong varint, extra bits ignored)
|
||||
&[0x0A, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x02],
|
||||
// tag 1 (overlong varint), type 2, length 0
|
||||
&[0x8A, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
|
||||
|
||||
// tag 2 (overlong varint), type 0
|
||||
&[0x90, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00],
|
||||
// tag 2 (overlong varint, extra bits ignored), type 0
|
||||
&[0x90, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x02, 0x00],
|
||||
];
|
||||
let requests = bad_requests.iter().chain(null_requests.iter());
|
||||
for request in requests.into_iter() {
|
||||
let scenario = Scenario::new();
|
||||
mocks::expect_enclave_messages(&scenario, vec![]);
|
||||
let mut kbupd_service = MockKbupdService {};
|
||||
kbupd_enclave_recv_untrusted_msg(&mut kbupd_service, request.as_ptr(), request.len());
|
||||
drop(scenario);
|
||||
}
|
||||
}
|
||||
}
|
||||
153
enclave/kbupd_enclave/src/ffi/mocks.rs
Normal file
153
enclave/kbupd_enclave/src/ffi/mocks.rs
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
use std::cell::{RefCell};
|
||||
use std;
|
||||
|
||||
use mockers::*;
|
||||
use mockers::matchers::*;
|
||||
use mockers_derive::mocked;
|
||||
use prost::{Message};
|
||||
|
||||
use crate::protobufs;
|
||||
|
||||
use super::bindgen_wrapper::{
|
||||
sgx_status_t,
|
||||
};
|
||||
|
||||
//
|
||||
// mock extern "C" functions
|
||||
//
|
||||
|
||||
thread_local! {
|
||||
pub static KBUPD_ENCLAVE_OCALL_RECV_ENCLAVE_MSG: RefCell<Option<KbupdEnclaveOcallRecvEnclaveMsgMock>> = RefCell::new(None);
|
||||
pub static KBUPD_ENCLAVE_OCALL_ALLOC: RefCell<Option<KbupdEnclaveOcallAllocMock>> = RefCell::new(None);
|
||||
}
|
||||
|
||||
#[mocked]
|
||||
pub trait KbupdEnclaveOcallRecvEnclaveMsg {
|
||||
fn enclave_message(&self, msg: protobufs::kbupd::enclave_message::Inner);
|
||||
fn kbupd_enclave_ocall_recv_enclave_msg(&self) -> sgx_status_t;
|
||||
}
|
||||
|
||||
#[mocked]
|
||||
pub trait KbupdEnclaveOcallAlloc {
|
||||
fn kbupd_enclave_ocall_alloc(&self, size: usize) -> Result<(*mut ::std::os::raw::c_void, usize), sgx_status_t>;
|
||||
}
|
||||
|
||||
impl MatchArg<protobufs::kbupd::enclave_message::Inner> for Box<dyn MatchArg<protobufs::kbupd::enclave_message::Inner>> {
|
||||
fn matches(&self, arg: &protobufs::kbupd::enclave_message::Inner) -> Result<(), String> { (**self).matches(arg) }
|
||||
fn describe(&self) -> String { (**self).describe() }
|
||||
}
|
||||
pub fn expect_enclave_messages(scenario: &Scenario, matchers: impl IntoIterator<Item = Box<dyn MatchArg<protobufs::kbupd::enclave_message::Inner>>>) {
|
||||
let mock = test_ffi::mock_for(&KBUPD_ENCLAVE_OCALL_RECV_ENCLAVE_MSG, &scenario);
|
||||
for matcher in matchers {
|
||||
scenario.expect(mock.enclave_message(matcher).and_return(()));
|
||||
}
|
||||
scenario.expect(mock.kbupd_enclave_ocall_recv_enclave_msg().and_return_clone(0).times(..));
|
||||
}
|
||||
|
||||
pub fn expect_kbupd_enclave_ocall_alloc(scenario: &Scenario,
|
||||
request_size: usize,
|
||||
returned_ptr: *mut libc::c_void,
|
||||
returned_size: usize) {
|
||||
assert_ne!(request_size, 0);
|
||||
let mock = test_ffi::mock_for(&KBUPD_ENCLAVE_OCALL_ALLOC, &scenario);
|
||||
scenario.expect(mock.kbupd_enclave_ocall_alloc(
|
||||
eq(request_size)
|
||||
).and_return(Ok((returned_ptr, returned_size))));
|
||||
|
||||
sgx_ffi::mocks::expect_sgx_is_outside_enclave(scenario, returned_ptr as *const libc::c_void, returned_size, true);
|
||||
}
|
||||
|
||||
//
|
||||
// mock extern "C" function implementations
|
||||
//
|
||||
|
||||
pub mod impls {
|
||||
use super::*;
|
||||
|
||||
struct OCallSlice(*const u8, usize);
|
||||
impl AsRef<[u8]> for OCallSlice {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
if self.1 != 0 {
|
||||
assert!(!self.0.is_null());
|
||||
unsafe { std::slice::from_raw_parts(self.0, self.1) }
|
||||
} else {
|
||||
unsafe { std::slice::from_raw_parts(1 as *const u8, 0) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn kbupd_enclave_ocall_recv_enclave_msg(data: *const u8, data_size: usize) -> sgx_status_t {
|
||||
let data = OCallSlice(data, data_size);
|
||||
let batch = protobufs::kbupd::EnclaveMessageBatch::decode(data.as_ref()).expect("bad EnclaveMessageBatch from enclave");
|
||||
KBUPD_ENCLAVE_OCALL_RECV_ENCLAVE_MSG.with(|mock_cell| {
|
||||
let mock_ref = mock_cell.borrow();
|
||||
let mock = mock_ref.as_ref().expect("no mock for kbupd_enclave_ocall_recv_enclave_msg");
|
||||
for msg in batch.messages {
|
||||
match msg.inner.expect("empty EnclaveMessage from enclave") {
|
||||
protobufs::kbupd::enclave_message::Inner::EnclaveLogSignal(log) => {
|
||||
eprintln!("enclave log: {}", std::str::from_utf8(&log.message).unwrap());
|
||||
}
|
||||
msg_inner => {
|
||||
mock.enclave_message(msg_inner);
|
||||
}
|
||||
}
|
||||
}
|
||||
mock.kbupd_enclave_ocall_recv_enclave_msg()
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn kbupd_enclave_ocall_alloc(p_ptr_out: *mut *mut ::std::os::raw::c_void, p_size_in_out: *mut usize) -> sgx_status_t {
|
||||
assert!(!p_ptr_out.is_null());
|
||||
assert!(!p_size_in_out.is_null());
|
||||
let size = unsafe { *p_size_in_out };
|
||||
assert_ne!(size, 0);
|
||||
let res = KBUPD_ENCLAVE_OCALL_ALLOC.with(|mock| {
|
||||
(mock.borrow().as_ref().expect("no mock for kbupd_enclave_ocall_alloc"))
|
||||
.kbupd_enclave_ocall_alloc(size)
|
||||
});
|
||||
match res {
|
||||
Ok((ptr, size)) => {
|
||||
unsafe {
|
||||
*p_ptr_out = ptr;
|
||||
*p_size_in_out = size;
|
||||
}
|
||||
0
|
||||
}
|
||||
Err(error) => error,
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn curve25519_donna(
|
||||
arg1: *mut ::std::os::raw::c_uchar,
|
||||
arg2: *const ::std::os::raw::c_uchar,
|
||||
arg3: *const ::std::os::raw::c_uchar,
|
||||
) -> ::std::os::raw::c_int {
|
||||
let arg1 = unsafe { std::slice::from_raw_parts_mut(arg1, 32) };
|
||||
let arg2 = unsafe { std::slice::from_raw_parts(arg2, 32) };
|
||||
let arg3 = unsafe { std::slice::from_raw_parts(arg3, 32) };
|
||||
test_ffi::read_rand(arg1);
|
||||
arg2.iter().for_each(|p| unsafe { std::ptr::read_volatile(p); });
|
||||
arg3.iter().for_each(|p| unsafe { std::ptr::read_volatile(p); });
|
||||
0
|
||||
}
|
||||
}
|
||||
25
enclave/kbupd_enclave/src/ffi/mod.rs
Normal file
25
enclave/kbupd_enclave/src/ffi/mod.rs
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#[allow(dead_code, non_camel_case_types, non_upper_case_globals, non_snake_case, improper_ctypes, clippy::all, clippy::pedantic, clippy::integer_arithmetic)]
|
||||
mod bindgen_wrapper;
|
||||
pub mod ecalls;
|
||||
#[cfg(not(any(test, feature = "test")))]
|
||||
mod panic;
|
||||
pub mod snow_resolver;
|
||||
|
||||
#[cfg(test)] pub mod mocks;
|
||||
30
enclave/kbupd_enclave/src/ffi/panic.rs
Normal file
30
enclave/kbupd_enclave/src/ffi/panic.rs
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
use alloc::string::{ToString};
|
||||
use core::panic::{PanicInfo};
|
||||
|
||||
use super::bindgen_wrapper::{kbupd_enclave_ocall_panic};
|
||||
|
||||
#[panic_handler]
|
||||
fn panic(info: &PanicInfo<'_>) -> ! {
|
||||
let message = info.to_string();
|
||||
unsafe {
|
||||
kbupd_enclave_ocall_panic(message.as_ptr(), message.len());
|
||||
libc::abort()
|
||||
}
|
||||
}
|
||||
391
enclave/kbupd_enclave/src/ffi/snow_resolver.rs
Normal file
391
enclave/kbupd_enclave/src/ffi/snow_resolver.rs
Normal file
@ -0,0 +1,391 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
use core::convert::{TryInto};
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
use rand_core::{RngCore, CryptoRng};
|
||||
use sgxsd_ffi::*;
|
||||
use snow::resolvers::*;
|
||||
use snow::types::*;
|
||||
use snow::params::*;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SnowResolver;
|
||||
|
||||
#[derive(Default)]
|
||||
struct SnowRdRand;
|
||||
|
||||
#[derive(Default)]
|
||||
struct SnowDh25519 {
|
||||
key: Curve25519Key,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct SnowHashSHA256 {
|
||||
context: SHA256Context,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct SnowCipherAESGCM {
|
||||
key: AesGcmKey,
|
||||
}
|
||||
|
||||
//
|
||||
// SnowResolver impls
|
||||
//
|
||||
|
||||
impl CryptoResolver for SnowResolver {
|
||||
fn resolve_rng(&self) -> Option<Box<dyn Random>> {
|
||||
Some(Box::new(SnowRdRand))
|
||||
}
|
||||
|
||||
fn resolve_dh(&self, choice: &DHChoice) -> Option<Box<dyn Dh>> {
|
||||
match *choice {
|
||||
DHChoice::Curve25519 => Some(Box::new(SnowDh25519::default())),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_hash(&self, choice: &HashChoice) -> Option<Box<dyn Hash>> {
|
||||
match *choice {
|
||||
HashChoice::SHA256 => Some(Box::new(SnowHashSHA256::default())),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_cipher(&self, choice: &CipherChoice) -> Option<Box<dyn Cipher>> {
|
||||
match *choice {
|
||||
CipherChoice::AESGCM => Some(Box::new(SnowCipherAESGCM::default())),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// SnowRdRand impls
|
||||
//
|
||||
|
||||
impl Random for SnowRdRand {}
|
||||
impl CryptoRng for SnowRdRand {}
|
||||
impl RngCore for SnowRdRand {
|
||||
fn next_u32(&mut self) -> u32 { RdRand.next_u32() }
|
||||
fn next_u64(&mut self) -> u64 { RdRand.next_u64() }
|
||||
fn fill_bytes(&mut self, dest: &mut [u8]) { RdRand.fill_bytes(dest) }
|
||||
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { RdRand.try_fill_bytes(dest) }
|
||||
}
|
||||
|
||||
//
|
||||
// SnowDh25519 impls
|
||||
//
|
||||
|
||||
impl Dh for SnowDh25519 {
|
||||
fn name(&self) -> &'static str { "25519" }
|
||||
fn pub_len(&self) -> usize { 32 }
|
||||
fn priv_len(&self) -> usize { 32 }
|
||||
fn set(&mut self, privkey: &[u8]) {
|
||||
let privkey: &[u8; 32] = privkey.try_into().unwrap_or_else(|_| panic!("overflow"));
|
||||
self.key.set_key(privkey);
|
||||
}
|
||||
fn generate(&mut self, rng: &mut dyn Random) {
|
||||
self.key.generate(rng);
|
||||
}
|
||||
fn pubkey(&self) -> &[u8] {
|
||||
self.key.pubkey()
|
||||
}
|
||||
fn privkey(&self) -> &[u8] {
|
||||
self.key.privkey()
|
||||
}
|
||||
fn dh(&self, pubkey: &[u8], out: &mut [u8]) -> Result<(), ()> {
|
||||
let pubkey: &[u8] = pubkey.get(..32).unwrap_or_else(|| panic!("overflow"));
|
||||
let pubkey: &[u8; 32] = pubkey.try_into().unwrap_or_else(|_| static_unreachable!());
|
||||
let out: &mut [u8] = out.get_mut(..32).unwrap_or_else(|| panic!("overflow"));
|
||||
let out: &mut [u8; 32] = out.try_into().unwrap_or_else(|_| static_unreachable!());
|
||||
self.key.dh(pubkey, out);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// SnowCipherAESGCM impls
|
||||
//
|
||||
|
||||
impl Cipher for SnowCipherAESGCM {
|
||||
fn name(&self) -> &'static str { "AESGCM" }
|
||||
fn set(&mut self, key: &[u8]) {
|
||||
let key: &[u8; 32] = key.try_into().unwrap_or_else(|_| panic!("overflow"));
|
||||
self.key.set_key(key);
|
||||
}
|
||||
fn encrypt(&self, nonce: u64, authtext: &[u8], plaintext: &[u8], out: &mut [u8]) -> usize {
|
||||
let (text_in_out, out) = out.split_at_mut(plaintext.len());
|
||||
let out: &mut [u8] = out.get_mut(..16).unwrap_or_else(|| panic!("overflow"));
|
||||
let out: &mut [u8; 16] = out.try_into().unwrap_or_else(|_| static_unreachable!());
|
||||
text_in_out.copy_from_slice(plaintext);
|
||||
|
||||
let mut mac = AesGcmMac::default();
|
||||
let mut iv = AesGcmIv::default();
|
||||
let iv_data: &mut [u8] = iv.data.get_mut(4..).unwrap_or_else(|| static_unreachable!());
|
||||
let iv_data: &mut [u8; 8] = iv_data.try_into().unwrap_or_else(|_| static_unreachable!());
|
||||
*iv_data = nonce.to_be_bytes();
|
||||
|
||||
match self.key.encrypt(text_in_out, authtext, &iv, &mut mac) {
|
||||
Ok(()) => {
|
||||
*out = mac.data;
|
||||
text_in_out.len().saturating_add(mac.data.len())
|
||||
}
|
||||
Err(_) => {
|
||||
sgx_ffi::util::clear(text_in_out);
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn decrypt(&self, nonce: u64, authtext: &[u8], ciphertext: &[u8], out: &mut [u8]) -> Result<usize, ()> {
|
||||
let ciphertext_len = ciphertext.len().checked_sub(16)
|
||||
.unwrap_or_else(|| panic!("overflow"));
|
||||
let (ciphertext, ciphertext_mac_data) = ciphertext.split_at(ciphertext_len);
|
||||
let ciphertext_mac_data: &[u8; 16] = ciphertext_mac_data.try_into().unwrap_or_else(|_| unreachable!());
|
||||
let (in_out_text, _) = out.split_at_mut(ciphertext.len());
|
||||
in_out_text.copy_from_slice(ciphertext);
|
||||
|
||||
let mac = AesGcmMac { data: *ciphertext_mac_data };
|
||||
let mut iv = AesGcmIv::default();
|
||||
let iv_data: &mut [u8] = iv.data.get_mut(4..).unwrap_or_else(|| static_unreachable!());
|
||||
let iv_data: &mut [u8; 8] = iv_data.try_into().unwrap_or_else(|_| static_unreachable!());
|
||||
*iv_data = nonce.to_be_bytes();
|
||||
|
||||
self.key.decrypt(in_out_text, authtext, &iv, &mac)
|
||||
.map(|()| in_out_text.len())
|
||||
.map_err(drop)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// SnowHashSHA256 impls
|
||||
//
|
||||
|
||||
impl Hash for SnowHashSHA256 {
|
||||
fn name(&self) -> &'static str { "SHA256" }
|
||||
fn block_len(&self) -> usize { 64 }
|
||||
fn hash_len(&self) -> usize { SHA256Context::hash_len() }
|
||||
fn reset(&mut self) {
|
||||
self.context.reset();
|
||||
}
|
||||
fn input(&mut self, data: &[u8]) {
|
||||
self.context.update(data);
|
||||
}
|
||||
fn result(&mut self, out: &mut [u8]) {
|
||||
let out: &mut [u8] = out.get_mut(..SHA256Context::hash_len()).unwrap_or_else(|| panic!("overflow"));
|
||||
let out: &mut [u8; SHA256Context::hash_len()] = out.try_into().unwrap_or_else(|_| static_unreachable!());
|
||||
self.context.result(out);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
|
||||
use mockers::*;
|
||||
use mockers::matchers::*;
|
||||
|
||||
#[test]
|
||||
fn resolve_rng_test() {
|
||||
let rand = SnowResolver.resolve_rng();
|
||||
assert!(rand.is_some());
|
||||
if let Some(mut rand) = rand {
|
||||
let mut data = vec![0; 100];
|
||||
rand.fill_bytes(&mut data[..0]);
|
||||
assert_eq!(&data[..], &vec![0; data.len()][..]);
|
||||
rand.fill_bytes(&mut data);
|
||||
assert_ne!(&data[..], &vec![0; data.len()][..]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_dh_test() {
|
||||
let dh = SnowResolver.resolve_dh(&DHChoice::Curve25519);
|
||||
let rand = SnowResolver.resolve_rng();
|
||||
assert!(dh.is_some());
|
||||
assert!(rand.is_some());
|
||||
if let (Some(mut dh), Some(mut rand)) = (dh, rand) {
|
||||
dh.generate(&mut *rand);
|
||||
let mut privkey = [0; 32];
|
||||
let mut pubkey = [0; 32];
|
||||
privkey.copy_from_slice(dh.privkey());
|
||||
pubkey.copy_from_slice(dh.pubkey());
|
||||
assert_ne!(&privkey, &[0; 32]);
|
||||
assert_ne!(&pubkey, &[0; 32]);
|
||||
|
||||
dh.set(&test_ffi::rand_bytes([0; 32]));
|
||||
assert_ne!(dh.privkey(), privkey);
|
||||
assert_ne!(dh.pubkey(), pubkey);
|
||||
|
||||
let mut res = vec![0; 32];
|
||||
dh.dh(&test_ffi::rand_bytes(vec![0; 32]), &mut res).unwrap();
|
||||
assert_ne!(&res[..], &[0; 32][..]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_dh_set_overflow() {
|
||||
let dh = SnowResolver.resolve_dh(&DHChoice::Curve25519);
|
||||
if let Some(mut dh) = dh {
|
||||
dh.set(&[0; 31]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_dh_pubkey_overflow() {
|
||||
let dh = SnowResolver.resolve_dh(&DHChoice::Curve25519);
|
||||
if let Some(dh) = dh {
|
||||
let _ignore = dh.dh(&test_ffi::rand_bytes(vec![0; 31]), &mut vec![0; 32]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_dh_out_overflow() {
|
||||
let dh = SnowResolver.resolve_dh(&DHChoice::Curve25519);
|
||||
if let Some(dh) = dh {
|
||||
let _ignore = dh.dh(&test_ffi::rand_bytes(vec![0; 32]), &mut vec![0; 31]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_hash_test() {
|
||||
let hash = SnowResolver.resolve_hash(&HashChoice::SHA256);
|
||||
assert!(hash.is_some());
|
||||
if let Some(mut hash) = hash {
|
||||
hash.reset();
|
||||
hash.input(&[]);
|
||||
hash.input(&[0]);
|
||||
hash.input(&test_ffi::rand_bytes(vec![0; 100]));
|
||||
let mut result = vec![0; hash.hash_len()];
|
||||
hash.result(&mut result);
|
||||
assert_ne!(&result[..], &vec![0; hash.hash_len()][..]);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! eq_vec {
|
||||
($vec:expr) => ({
|
||||
let vec: Vec<u8> = $vec.clone();
|
||||
check(move |slice: &&[u8]| slice == &&vec[..])
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_cipher_test() {
|
||||
let cipher = SnowResolver.resolve_cipher(&CipherChoice::AESGCM);
|
||||
assert!(cipher.is_some());
|
||||
if let Some(mut cipher) = cipher {
|
||||
let privkey = test_ffi::rand_bytes(vec![0; 32]);
|
||||
cipher.set(&privkey);
|
||||
|
||||
test_ffi::clear(&sgxsd_ffi::mocks::SGXSD_AES_GCM_ENCRYPT);
|
||||
|
||||
let authtext = vec![0; 100];
|
||||
let plaintext = vec![0; 100];
|
||||
let mut out = vec![0; plaintext.len() + 16];
|
||||
assert_eq!(cipher.encrypt(0, &authtext, &plaintext, &mut out), out.len());
|
||||
assert_ne!(&vec![0; 8][..], &out[..8]);
|
||||
assert_ne!(&vec![0; 8][..], &out[(out.len() - 8)..]);
|
||||
|
||||
test_ffi::clear(&sgxsd_ffi::mocks::SGXSD_AES_GCM_DECRYPT);
|
||||
|
||||
let ciphertext = vec![0; plaintext.len() + 16];
|
||||
let mut out = vec![0; plaintext.len()];
|
||||
assert_eq!(cipher.decrypt(0, &authtext, &ciphertext, &mut out), Ok(out.len()));
|
||||
assert_ne!(&out[..], &vec![0; out.len()][..]);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_cipher_success() {
|
||||
let scenario = Scenario::new();
|
||||
let mut cipher = SnowResolver.resolve_cipher(&CipherChoice::AESGCM).unwrap();
|
||||
let privkey = test_ffi::rand_bytes(vec![0; 32]);
|
||||
let authtext = test_ffi::rand_bytes(vec![0; 100]);
|
||||
let plaintext = test_ffi::rand_bytes(vec![0; 100]);
|
||||
let ciphertext = test_ffi::rand_bytes(vec![0; 100]);
|
||||
|
||||
cipher.set(&privkey);
|
||||
|
||||
let mock = test_ffi::mock_for(&sgxsd_ffi::mocks::SGXSD_AES_GCM_ENCRYPT, &scenario);
|
||||
scenario.expect(mock.sgxsd_aes_gcm_encrypt(
|
||||
eq_vec!(privkey),
|
||||
eq_vec!(plaintext),
|
||||
any(),
|
||||
eq_vec!(authtext)
|
||||
).and_return(Ok(ciphertext.clone())));
|
||||
|
||||
let mut ciphertext_and_tag_out = vec![0; plaintext.len() + 16];
|
||||
assert_eq!(cipher.encrypt(0, &authtext, &plaintext, &mut ciphertext_and_tag_out), ciphertext_and_tag_out.len());
|
||||
assert_eq!(&ciphertext_and_tag_out[..ciphertext.len()], &ciphertext[..]);
|
||||
|
||||
let mock = test_ffi::mock_for(&sgxsd_ffi::mocks::SGXSD_AES_GCM_DECRYPT, &scenario);
|
||||
scenario.expect(mock.sgxsd_aes_gcm_decrypt(
|
||||
eq_vec!(privkey),
|
||||
eq_vec!(ciphertext),
|
||||
any(),
|
||||
eq_vec!(authtext)
|
||||
).and_return(Ok(plaintext.clone())));
|
||||
|
||||
let mut plaintext_out = vec![0; plaintext.len()];
|
||||
assert_eq!(cipher.decrypt(0, &authtext, &ciphertext_and_tag_out, &mut plaintext_out), Ok(plaintext_out.len()));
|
||||
assert_eq!(&plaintext_out, &plaintext);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_cipher_fail() {
|
||||
let scenario = Scenario::new();
|
||||
let mut cipher = SnowResolver.resolve_cipher(&CipherChoice::AESGCM).unwrap();
|
||||
let privkey = test_ffi::rand_bytes(vec![0; 32]);
|
||||
let authtext = test_ffi::rand_bytes(vec![0; 100]);
|
||||
let plaintext = test_ffi::rand_bytes(vec![0; 100]);
|
||||
let ciphertext = test_ffi::rand_bytes(vec![0; 100]);
|
||||
|
||||
cipher.set(&privkey);
|
||||
|
||||
let mock = test_ffi::mock_for(&sgxsd_ffi::mocks::SGXSD_AES_GCM_ENCRYPT, &scenario);
|
||||
scenario.expect(mock.sgxsd_aes_gcm_encrypt(
|
||||
eq_vec!(privkey),
|
||||
eq_vec!(plaintext),
|
||||
any(),
|
||||
eq_vec!(authtext)
|
||||
).and_return(Err(())));
|
||||
|
||||
let mut ciphertext_and_tag_out = vec![0; plaintext.len() + 16];
|
||||
assert_eq!(cipher.encrypt(0, &authtext, &plaintext, &mut ciphertext_and_tag_out), 0);
|
||||
assert_eq!(&ciphertext_and_tag_out, &vec![0; ciphertext_and_tag_out.len()]);
|
||||
|
||||
let mock = test_ffi::mock_for(&sgxsd_ffi::mocks::SGXSD_AES_GCM_DECRYPT, &scenario);
|
||||
scenario.expect(mock.sgxsd_aes_gcm_decrypt(
|
||||
eq_vec!(privkey),
|
||||
eq_vec!(ciphertext),
|
||||
any(),
|
||||
eq_vec!(authtext)
|
||||
).and_return(Err(())));
|
||||
|
||||
ciphertext_and_tag_out[..ciphertext.len()].copy_from_slice(&ciphertext);
|
||||
let mut plaintext_out = ciphertext.clone();
|
||||
assert_eq!(cipher.decrypt(0, &authtext, &ciphertext_and_tag_out, &mut plaintext_out), Err(()));
|
||||
assert_eq!(&plaintext_out, &ciphertext);
|
||||
}
|
||||
}
|
||||
39
enclave/kbupd_enclave/src/hasher.rs
Normal file
39
enclave/kbupd_enclave/src/hasher.rs
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#![allow(deprecated)]
|
||||
|
||||
use core::hash::{BuildHasher, SipHasher};
|
||||
|
||||
use rand_core::{RngCore};
|
||||
use sgxsd_ffi::{RdRand};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DefaultHasher(u64, u64);
|
||||
|
||||
impl Default for DefaultHasher {
|
||||
fn default() -> Self {
|
||||
Self(RdRand.next_u64(), RdRand.next_u64())
|
||||
}
|
||||
}
|
||||
|
||||
impl BuildHasher for DefaultHasher {
|
||||
type Hasher = SipHasher;
|
||||
fn build_hasher(&self) -> Self::Hasher {
|
||||
SipHasher::new_with_keys(self.0, self.1)
|
||||
}
|
||||
}
|
||||
291
enclave/kbupd_enclave/src/kbupd_enclave.proto
Normal file
291
enclave/kbupd_enclave/src/kbupd_enclave.proto
Normal file
@ -0,0 +1,291 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package protobufs.kbupd_enclave;
|
||||
|
||||
import "kbupd.proto";
|
||||
import "kbupd_client.proto";
|
||||
import "raft.proto";
|
||||
|
||||
message SecretBytes {
|
||||
required bytes data = 1;
|
||||
}
|
||||
|
||||
//
|
||||
// transactions
|
||||
//
|
||||
|
||||
message TransactionData {
|
||||
oneof inner {
|
||||
FrontendRequestTransaction frontend_request = 1;
|
||||
StartXferTransaction start_xfer = 2;
|
||||
SetSidTransaction set_sid = 3;
|
||||
RemoveChunkTransaction remove_chunk = 4;
|
||||
ApplyChunkTransaction apply_chunk = 5;
|
||||
PauseXferTransaction pause_xfer = 6;
|
||||
ResumeXferTransaction resume_xfer = 7;
|
||||
FinishXferTransaction finish_xfer = 8;
|
||||
SetTimeTransaction set_time = 9;
|
||||
};
|
||||
}
|
||||
message FrontendRequestTransaction {
|
||||
required bytes from_node_id = 1;
|
||||
required uint64 request_id = 2;
|
||||
oneof transaction {
|
||||
CreateBackupTransaction create = 3;
|
||||
BackupTransaction backup = 4;
|
||||
RestoreTransaction restore = 5;
|
||||
DeleteBackupTransaction delete = 6;
|
||||
};
|
||||
}
|
||||
|
||||
message CreateBackupTransaction {
|
||||
required kbupd.BackupId backup_id = 1;
|
||||
required bytes new_creation_nonce = 2;
|
||||
required bytes new_nonce = 3;
|
||||
}
|
||||
message BackupTransaction {
|
||||
required kbupd.BackupId backup_id = 1;
|
||||
required bytes old_nonce = 2;
|
||||
required bytes new_creation_nonce = 3;
|
||||
required bytes new_nonce = 4;
|
||||
required SecretBytes data = 5;
|
||||
required SecretBytes pin = 6;
|
||||
required uint32 tries = 7;
|
||||
}
|
||||
message RestoreTransaction {
|
||||
required kbupd.BackupId backup_id = 1;
|
||||
required bytes creation_nonce = 2;
|
||||
required bytes old_nonce = 3;
|
||||
required bytes new_nonce = 4;
|
||||
required SecretBytes pin = 5;
|
||||
}
|
||||
message DeleteBackupTransaction {
|
||||
required kbupd.BackupId backup_id = 1;
|
||||
}
|
||||
message StartXferTransaction {
|
||||
required bytes from_node_id = 1;
|
||||
required XferRequest xfer_request = 2;
|
||||
}
|
||||
message SetSidTransaction {
|
||||
required bytes from_node_id = 1;
|
||||
required kbupd.ServiceId service_id = 2;
|
||||
}
|
||||
message RemoveChunkTransaction {
|
||||
required bytes from_node_id = 1;
|
||||
required XferChunkReply xfer_chunk_reply = 2;
|
||||
required kbupd.BackupId chunk_last = 3;
|
||||
}
|
||||
message ApplyChunkTransaction {
|
||||
required bytes from_node_id = 1;
|
||||
required XferChunkRequest xfer_chunk_request = 2;
|
||||
required XferChunkReply xfer_chunk_reply = 3;
|
||||
}
|
||||
message PauseXferTransaction {
|
||||
required uint64 request_id = 1;
|
||||
}
|
||||
message ResumeXferTransaction {
|
||||
required uint64 request_id = 1;
|
||||
required kbupd.BackupId chunk_last = 2;
|
||||
}
|
||||
message FinishXferTransaction {
|
||||
required uint64 request_id = 1;
|
||||
required bool force = 2;
|
||||
}
|
||||
message SetTimeTransaction {
|
||||
required uint64 now_secs = 1;
|
||||
}
|
||||
|
||||
//
|
||||
// remote enclave handshake
|
||||
//
|
||||
|
||||
enum NodeType {
|
||||
NODE_TYPE_NONE = 0;
|
||||
NODE_TYPE_FRONTEND = 1;
|
||||
NODE_TYPE_REPLICA = 2;
|
||||
}
|
||||
|
||||
message PeerConnectRequest {
|
||||
required NodeType node_type = 1;
|
||||
optional kbupd.IasReport ias_report = 2;
|
||||
required bytes noise_data = 3;
|
||||
}
|
||||
|
||||
message PeerConnectReply {
|
||||
required bytes sgx_quote = 1;
|
||||
required bytes noise_data = 2;
|
||||
}
|
||||
|
||||
//
|
||||
// enclave-to-enclave requests
|
||||
//
|
||||
|
||||
message EnclaveGetQuoteRequest {
|
||||
}
|
||||
|
||||
message EnclaveGetQuoteReply {
|
||||
required bytes sgx_quote = 1;
|
||||
}
|
||||
|
||||
//
|
||||
// frontend to replica
|
||||
//
|
||||
|
||||
message FrontendToReplicaMessage {
|
||||
oneof inner {
|
||||
TransactionRequest transaction_request = 1;
|
||||
EnclaveGetQuoteRequest enclave_get_quote_request = 2;
|
||||
};
|
||||
}
|
||||
|
||||
message TransactionRequest {
|
||||
required uint64 request_id = 1;
|
||||
oneof data {
|
||||
kbupd.CreateBackupRequest create = 2;
|
||||
BackupTransactionRequest backup = 3;
|
||||
RestoreTransactionRequest restore = 4;
|
||||
DeleteTransactionRequest delete = 5;
|
||||
};
|
||||
}
|
||||
|
||||
message BackupTransactionRequest {
|
||||
optional bytes service_id = 1;
|
||||
required kbupd.BackupId backup_id = 2;
|
||||
required bytes nonce = 3;
|
||||
required uint64 valid_from = 4;
|
||||
required SecretBytes data = 5;
|
||||
required SecretBytes pin = 6;
|
||||
required uint32 tries = 7;
|
||||
}
|
||||
|
||||
message RestoreTransactionRequest {
|
||||
optional bytes service_id = 1;
|
||||
required kbupd.BackupId backup_id = 2;
|
||||
required bytes nonce = 3;
|
||||
required uint64 valid_from = 4;
|
||||
required SecretBytes pin = 5;
|
||||
}
|
||||
|
||||
message DeleteTransactionRequest {
|
||||
optional bytes service_id = 1;
|
||||
required kbupd.BackupId backup_id = 2;
|
||||
}
|
||||
|
||||
//
|
||||
// replica to frontend
|
||||
//
|
||||
|
||||
message ReplicaToFrontendMessage {
|
||||
oneof inner {
|
||||
TransactionReply transaction_reply = 1;
|
||||
EnclaveGetQuoteReply enclave_get_quote_reply = 2;
|
||||
};
|
||||
}
|
||||
|
||||
message TransactionReply {
|
||||
required uint64 request_id = 1;
|
||||
oneof data {
|
||||
kbupd_client.Response client_response = 2;
|
||||
kbupd.CreateBackupReply create_backup_reply = 3;
|
||||
kbupd.DeleteBackupReply delete_backup_reply = 4;
|
||||
TransactionErrorNotLeader not_leader = 5;
|
||||
TransactionErrorWrongPartition wrong_partition = 6;
|
||||
TransactionErrorServiceIdMismatch service_id_mismatch = 7;
|
||||
TransactionErrorXferInProgress xfer_in_progress = 8;
|
||||
TransactionErrorInvalidRequest invalid_request = 9;
|
||||
TransactionErrorInternalError internal_error = 10;
|
||||
};
|
||||
}
|
||||
|
||||
message TransactionErrorNotLeader {
|
||||
optional bytes leader_node_id = 1;
|
||||
required raft.TermId term = 2;
|
||||
}
|
||||
|
||||
message TransactionErrorWrongPartition {
|
||||
optional kbupd.PartitionKeyRangePB range = 1;
|
||||
optional kbupd.PartitionConfig new_partition = 2;
|
||||
}
|
||||
|
||||
message TransactionErrorServiceIdMismatch {
|
||||
}
|
||||
|
||||
message TransactionErrorXferInProgress {
|
||||
}
|
||||
|
||||
message TransactionErrorInvalidRequest {
|
||||
}
|
||||
|
||||
message TransactionErrorInternalError {
|
||||
}
|
||||
|
||||
//
|
||||
// replica to replica
|
||||
//
|
||||
|
||||
message ReplicaToReplicaMessage {
|
||||
oneof inner {
|
||||
raft.RaftMessage raft_message = 1;
|
||||
CreateRaftGroupRequest create_raft_group_request = 2;
|
||||
EnclaveGetQuoteRequest enclave_get_quote_request = 8;
|
||||
EnclaveGetQuoteReply enclave_get_quote_reply = 9;
|
||||
|
||||
XferRequest xfer_request = 3;
|
||||
XferReply xfer_reply = 4;
|
||||
XferChunkRequest xfer_chunk_request = 5;
|
||||
XferChunkReply xfer_chunk_reply = 6;
|
||||
XferErrorNotLeader xfer_error_not_leader = 7;
|
||||
};
|
||||
}
|
||||
|
||||
message CreateRaftGroupRequest {
|
||||
optional kbupd.ServiceId service_id = 1;
|
||||
required raft.RaftGroupId group_id = 2;
|
||||
repeated bytes node_ids = 3;
|
||||
required kbupd.EnclaveReplicaGroupConfig config = 4;
|
||||
optional kbupd.SourcePartitionConfig source_partition = 5;
|
||||
}
|
||||
|
||||
message XferRequest {
|
||||
required uint32 chunk_size = 1;
|
||||
required kbupd.PartitionKeyRangePB full_range = 2;
|
||||
repeated bytes node_ids = 3;
|
||||
required raft.RaftGroupId group_id = 4;
|
||||
}
|
||||
|
||||
message XferReply {
|
||||
required kbupd.ServiceId service = 1;
|
||||
}
|
||||
|
||||
message XferChunkRequest {
|
||||
required SecretBytes data = 1;
|
||||
required kbupd.PartitionKeyRangePB chunk_range = 2;
|
||||
required kbupd.AttestationParameters min_attestation = 3;
|
||||
}
|
||||
|
||||
message XferChunkReply {
|
||||
required kbupd.BackupId new_last = 1;
|
||||
required uint32 chunk_size = 2;
|
||||
}
|
||||
|
||||
message XferErrorNotLeader {
|
||||
optional bytes leader_node_id = 1;
|
||||
required raft.TermId term = 2;
|
||||
}
|
||||
137
enclave/kbupd_enclave/src/lib.rs
Normal file
137
enclave/kbupd_enclave/src/lib.rs
Normal file
@ -0,0 +1,137 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#![crate_type = "staticlib"]
|
||||
#![cfg_attr(not(any(test, feature = "test")), no_std)]
|
||||
#![cfg_attr(not(any(test, feature = "test")), feature(alloc_error_handler))]
|
||||
#![cfg_attr(not(any(test, feature = "test")), feature(thread_local))]
|
||||
#![allow(
|
||||
unused_parens,
|
||||
clippy::style,
|
||||
clippy::large_enum_variant,
|
||||
)]
|
||||
#![warn(
|
||||
bare_trait_objects,
|
||||
elided_lifetimes_in_paths,
|
||||
trivial_numeric_casts,
|
||||
variant_size_differences,
|
||||
clippy::integer_arithmetic,
|
||||
clippy::wildcard_enum_match_arm,
|
||||
)]
|
||||
#![deny(
|
||||
clippy::cast_possible_truncation,
|
||||
clippy::cast_possible_wrap,
|
||||
clippy::cast_precision_loss,
|
||||
clippy::cast_sign_loss,
|
||||
clippy::clone_on_ref_ptr,
|
||||
clippy::expl_impl_clone_on_copy,
|
||||
clippy::explicit_into_iter_loop,
|
||||
clippy::explicit_iter_loop,
|
||||
clippy::float_arithmetic,
|
||||
clippy::float_cmp_const,
|
||||
clippy::indexing_slicing,
|
||||
clippy::maybe_infinite_iter,
|
||||
clippy::mem_forget,
|
||||
clippy::mut_mut,
|
||||
clippy::needless_borrow,
|
||||
clippy::option_unwrap_used,
|
||||
clippy::panicking_unwrap,
|
||||
clippy::print_stdout,
|
||||
clippy::redundant_clone,
|
||||
clippy::replace_consts,
|
||||
clippy::result_unwrap_used,
|
||||
clippy::shadow_unrelated,
|
||||
clippy::unimplemented,
|
||||
clippy::use_debug,
|
||||
clippy::use_self,
|
||||
clippy::use_underscore_binding,
|
||||
)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg(not(any(test, feature = "test")))]
|
||||
extern crate no_std_compat as std;
|
||||
|
||||
#[cfg(not(any(test, feature = "test")))]
|
||||
#[global_allocator]
|
||||
static ALLOCATOR: allocator::System = allocator::System;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
#[cfg(not(any(test, feature = "test")))]
|
||||
mod allocator;
|
||||
mod ffi;
|
||||
mod hasher;
|
||||
mod logging;
|
||||
mod lru;
|
||||
mod prelude;
|
||||
#[allow(clippy::all, clippy::pedantic, clippy::integer_arithmetic)]
|
||||
mod protobufs;
|
||||
mod protobufs_impl;
|
||||
mod service;
|
||||
mod storage;
|
||||
mod raft;
|
||||
mod remote;
|
||||
mod remote_group;
|
||||
mod util;
|
||||
|
||||
pub use crate::ffi::ecalls::{
|
||||
kbupd_send,
|
||||
kbupd_send_flush,
|
||||
};
|
||||
|
||||
pub mod external {
|
||||
use sgx_ffi::sgx::{SgxStatus};
|
||||
use sgxsd_ffi::ecalls::{SgxsdServer};
|
||||
|
||||
use crate::service::main;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn sgxsd_enclave_server_init(p_args: *const <main::SgxsdState as SgxsdServer>::InitArgs,
|
||||
pp_state: *mut *mut main::SgxsdState)
|
||||
-> SgxStatus
|
||||
{
|
||||
sgxsd_ffi::ecalls::sgxsd_enclave_server_init(p_args, pp_state)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn sgxsd_enclave_server_handle_call(p_args: *const <main::SgxsdState as SgxsdServer>::HandleCallArgs,
|
||||
msg_buf: sgxsd_ffi::ecalls::sgxsd_msg_buf_t,
|
||||
mut from: sgxsd_ffi::ecalls::sgxsd_msg_from_t,
|
||||
pp_state: *mut *mut main::SgxsdState)
|
||||
-> SgxStatus
|
||||
{
|
||||
sgxsd_ffi::ecalls::sgxsd_enclave_server_handle_call(p_args, msg_buf, &mut from, pp_state)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn sgxsd_enclave_server_terminate(p_args: *const <main::SgxsdState as SgxsdServer>::TerminateArgs,
|
||||
p_state: *mut main::SgxsdState)
|
||||
-> SgxStatus
|
||||
{
|
||||
sgxsd_ffi::ecalls::sgxsd_enclave_server_terminate(p_args, p_state)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn kbupd_enclave_recv_untrusted_msg(p_data: *const u8, data_size: usize) {
|
||||
crate::service::main::whereis(|service_ref| {
|
||||
let mut service = service_ref.borrow_mut();
|
||||
crate::ffi::ecalls::kbupd_enclave_recv_untrusted_msg(&mut *service, p_data, data_size)
|
||||
});
|
||||
}
|
||||
}
|
||||
28
enclave/kbupd_enclave/src/logging.rs
Normal file
28
enclave/kbupd_enclave/src/logging.rs
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
static VERBOSE: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
pub fn verbose_logging_enabled() -> bool {
|
||||
VERBOSE.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub fn set_verbose_logging_enabled(enabled: bool) {
|
||||
VERBOSE.store(enabled, Ordering::SeqCst)
|
||||
}
|
||||
120
enclave/kbupd_enclave/src/lru.rs
Normal file
120
enclave/kbupd_enclave/src/lru.rs
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
use intrusive_collections::*;
|
||||
use intrusive_collections::{LinkedList};
|
||||
|
||||
use std::rc::*;
|
||||
|
||||
pub struct Lru<T> {
|
||||
list: LinkedList<LruAdapter<T>>,
|
||||
token: Rc<LruToken>,
|
||||
length: usize,
|
||||
}
|
||||
|
||||
pub struct LruEntry<T> {
|
||||
item: T,
|
||||
token: Weak<LruToken>,
|
||||
link: LinkedListLink,
|
||||
}
|
||||
|
||||
intrusive_adapter!(pub LruAdapter<T> = Rc<LruEntry<T>>: LruEntry<T> { link: LinkedListLink });
|
||||
|
||||
struct LruToken;
|
||||
|
||||
impl<T> Lru<T> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
list: LinkedList::new(LruAdapter::new()),
|
||||
token: Rc::new(LruToken),
|
||||
length: Default::default(),
|
||||
}
|
||||
}
|
||||
pub fn len(&self) -> usize {
|
||||
self.length
|
||||
}
|
||||
pub fn push_back(&mut self, item: T) -> Weak<LruEntry<T>> {
|
||||
let lru_entry = Rc::new(LruEntry {
|
||||
item,
|
||||
token: Rc::downgrade(&self.token),
|
||||
link: Default::default()
|
||||
});
|
||||
let lru_entry_weak = Rc::downgrade(&lru_entry);
|
||||
|
||||
self.list.push_back(lru_entry);
|
||||
self.length = self.length.saturating_add(1);
|
||||
lru_entry_weak
|
||||
}
|
||||
pub fn bump(&mut self, lru_entry_weak: &Weak<LruEntry<T>>) -> bool {
|
||||
if let Some(lru_entry) = lru_entry_weak.upgrade() {
|
||||
// check that lru_entry is a member of self.list
|
||||
if let Some(lru_entry_token) = lru_entry.token.upgrade() {
|
||||
if !Rc::ptr_eq(&lru_entry_token, &self.token) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if !lru_entry.link.is_linked() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// safety: lru_entry must be a member of self.list
|
||||
let mut lru_cursor = unsafe {
|
||||
self.list.cursor_mut_from_ptr(lru_entry.as_ref())
|
||||
};
|
||||
if let Some(lru_entry_rc) = lru_cursor.remove() {
|
||||
self.list.push_back(lru_entry_rc);
|
||||
} else {
|
||||
self.list.push_back(lru_entry);
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
pub fn pop_front(&mut self) -> Option<Rc<LruEntry<T>>> {
|
||||
if let Some(lru_entry) = self.list.pop_front() {
|
||||
self.length = self.length.saturating_sub(1);
|
||||
Some(lru_entry)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for Lru<T> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> LruEntry<T> {
|
||||
pub fn get(&self) -> &T {
|
||||
&self.item
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'a, T> IntoIterator for &'a Lru<T> {
|
||||
type Item = &'a LruEntry<T>;
|
||||
type IntoIter = linked_list::Iter<'a, LruAdapter<T>>;
|
||||
|
||||
fn into_iter(self) -> linked_list::Iter<'a, LruAdapter<T>> {
|
||||
self.list.iter()
|
||||
}
|
||||
}
|
||||
101
enclave/kbupd_enclave/src/macros.rs
Normal file
101
enclave/kbupd_enclave/src/macros.rs
Normal file
@ -0,0 +1,101 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
macro_rules! error {
|
||||
($($arg:tt)*) => (log!($crate::protobufs::kbupd::EnclaveLogLevel::Error, $($arg)*));
|
||||
}
|
||||
macro_rules! warn {
|
||||
($($arg:tt)*) => (log!($crate::protobufs::kbupd::EnclaveLogLevel::Warn, $($arg)*));
|
||||
}
|
||||
macro_rules! info {
|
||||
($($arg:tt)*) => (log!($crate::protobufs::kbupd::EnclaveLogLevel::Info, $($arg)*));
|
||||
}
|
||||
macro_rules! verbose {
|
||||
($($arg:tt)*) => (
|
||||
if $crate::logging::verbose_logging_enabled() {
|
||||
log!($crate::protobufs::kbupd::EnclaveLogLevel::Info, $($arg)*)
|
||||
} else {
|
||||
#[cfg(feature = "debug")]
|
||||
log!($crate::protobufs::kbupd::EnclaveLogLevel::Info, $($arg)*)
|
||||
}
|
||||
);
|
||||
}
|
||||
macro_rules! debug {
|
||||
($($arg:tt)*) => ({
|
||||
#[cfg(feature = "debug")]
|
||||
#[cfg(feature = "insecure")]
|
||||
log!($crate::protobufs::kbupd::EnclaveLogLevel::Debug, $($arg)*)
|
||||
});
|
||||
}
|
||||
|
||||
macro_rules! log {
|
||||
($level:expr, $msg:expr) => ({
|
||||
log!($level, "{}", $msg)
|
||||
});
|
||||
($level:expr, $msg:expr,) => ({
|
||||
log!($level, $msg)
|
||||
});
|
||||
($level:expr, $fmt:expr, $($arg:tt)*) => ({
|
||||
$crate::kbupd_send($crate::protobufs::kbupd::EnclaveMessage {
|
||||
inner: Some($crate::protobufs::kbupd::enclave_message::Inner::EnclaveLogSignal($crate::protobufs::kbupd::EnclaveLogSignal {
|
||||
message: ::alloc::format!($fmt, $($arg)*).into_bytes(),
|
||||
module: module_path!().as_bytes().to_vec(),
|
||||
file: file!().rsplit("/").next().unwrap_or_default().as_bytes().to_vec(),
|
||||
line: line!(),
|
||||
level: $level.into(),
|
||||
})),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
macro_rules! assert_true {
|
||||
($($arg:tt)*) => ({
|
||||
assert!($($arg)+);
|
||||
true
|
||||
});
|
||||
}
|
||||
|
||||
macro_rules! assert_match {
|
||||
($pat:pat = $expr:expr) => ({
|
||||
if let $pat = $expr {
|
||||
true
|
||||
} else {
|
||||
panic!("assertion failed: `$pat = $expr`")
|
||||
}
|
||||
});
|
||||
($pat:pat = $expr:expr, $($arg:tt)*) => ({
|
||||
if let $pat = $expr {
|
||||
true
|
||||
} else {
|
||||
panic!("assertion failed: `$pat = $expr`: {}", format_args!($($arg)+))
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
macro_rules! static_unreachable {
|
||||
() => ({
|
||||
#[cfg(not(debug_assertions))]
|
||||
{
|
||||
extern "C" {
|
||||
pub fn __static_unreachable() -> !;
|
||||
}
|
||||
unsafe { __static_unreachable() };
|
||||
}
|
||||
#[cfg(debug_assertions)]
|
||||
unreachable!()
|
||||
})
|
||||
}
|
||||
22
enclave/kbupd_enclave/src/prelude.rs
Normal file
22
enclave/kbupd_enclave/src/prelude.rs
Normal file
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
pub use alloc::{format, vec};
|
||||
pub use alloc::borrow::{ToOwned};
|
||||
pub use alloc::boxed::{Box};
|
||||
pub use alloc::string::{String, ToString};
|
||||
pub use alloc::vec::{Vec};
|
||||
25
enclave/kbupd_enclave/src/protobufs.proto
Normal file
25
enclave/kbupd_enclave/src/protobufs.proto
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package protobufs;
|
||||
|
||||
import "kbupd.proto";
|
||||
import "kbupd_client.proto";
|
||||
import "raft.proto";
|
||||
import "kbupd_enclave.proto";
|
||||
722
enclave/kbupd_enclave/src/protobufs/kbupd.rs
Normal file
722
enclave/kbupd_enclave/src/protobufs/kbupd.rs
Normal file
@ -0,0 +1,722 @@
|
||||
//
|
||||
// shared types
|
||||
//
|
||||
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ServiceId {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub id: std::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct BackupId {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub id: std::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct PartitionKeyRangePb {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub first: BackupId,
|
||||
#[prost(message, required, tag="2")]
|
||||
pub last: BackupId,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct IasReport {
|
||||
#[prost(bytes, required, tag="2")]
|
||||
pub body: std::vec::Vec<u8>,
|
||||
#[prost(bytes, required, tag="3")]
|
||||
pub signature: std::vec::Vec<u8>,
|
||||
#[prost(bytes, repeated, tag="4")]
|
||||
pub certificates: ::std::vec::Vec<std::vec::Vec<u8>>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct AttestationParameters {
|
||||
#[prost(uint64, required, tag="1")]
|
||||
pub unix_timestamp_seconds: u64,
|
||||
}
|
||||
//
|
||||
// transaction requests
|
||||
//
|
||||
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct CreateBackupRequest {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub backup_id: BackupId,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct CreateBackupReply {
|
||||
#[prost(bytes, required, tag="2")]
|
||||
pub nonce: std::vec::Vec<u8>,
|
||||
#[prost(uint32, optional, tag="3")]
|
||||
pub tries: ::std::option::Option<u32>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct DeleteBackupRequest {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub backup_id: BackupId,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct DeleteBackupReply {
|
||||
}
|
||||
//
|
||||
// untrusted messages
|
||||
//
|
||||
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct UntrustedMessageBatch {
|
||||
#[prost(message, repeated, tag="1")]
|
||||
pub messages: ::std::vec::Vec<UntrustedMessage>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct UntrustedMessage {
|
||||
#[prost(oneof="untrusted_message::Inner", tags="1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16")]
|
||||
pub inner: ::std::option::Option<untrusted_message::Inner>,
|
||||
}
|
||||
pub mod untrusted_message {
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Inner {
|
||||
#[prost(message, tag="1")]
|
||||
StartFrontendRequest(super::StartFrontendRequest),
|
||||
#[prost(message, tag="2")]
|
||||
StartReplicaRequest(super::StartReplicaRequest),
|
||||
#[prost(message, tag="3")]
|
||||
StartReplicaGroupRequest(super::StartReplicaGroupRequest),
|
||||
#[prost(message, tag="4")]
|
||||
UntrustedTransactionRequest(super::UntrustedTransactionRequest),
|
||||
#[prost(message, tag="5")]
|
||||
UntrustedXferRequest(super::UntrustedXferRequest),
|
||||
#[prost(message, tag="6")]
|
||||
GetEnclaveStatusRequest(super::GetEnclaveStatusRequest),
|
||||
#[prost(message, tag="8")]
|
||||
GetQeInfoReply(super::GetQeInfoReply),
|
||||
#[prost(message, tag="9")]
|
||||
GetQuoteReply(super::GetQuoteReply),
|
||||
#[prost(message, tag="10")]
|
||||
GetAttestationReply(super::GetAttestationReply),
|
||||
#[prost(message, tag="11")]
|
||||
NewMessageSignal(super::NewMessageSignal),
|
||||
#[prost(message, tag="12")]
|
||||
TimerTickSignal(super::TimerTickSignal),
|
||||
#[prost(message, tag="13")]
|
||||
SetFrontendConfigSignal(super::SetFrontendConfigSignal),
|
||||
#[prost(message, tag="14")]
|
||||
SetReplicaConfigSignal(super::SetReplicaConfigSignal),
|
||||
#[prost(message, tag="15")]
|
||||
ResetPeerSignal(super::ResetPeerSignal),
|
||||
#[prost(message, tag="16")]
|
||||
SetVerboseLoggingSignal(super::SetVerboseLoggingSignal),
|
||||
}
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct PartitionConfig {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub group_id: std::vec::Vec<u8>,
|
||||
#[prost(message, optional, tag="2")]
|
||||
pub range: ::std::option::Option<PartitionKeyRangePb>,
|
||||
#[prost(bytes, repeated, tag="3")]
|
||||
pub node_ids: ::std::vec::Vec<std::vec::Vec<u8>>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct StartFrontendRequest {
|
||||
#[prost(message, repeated, tag="1")]
|
||||
pub partitions: ::std::vec::Vec<PartitionConfig>,
|
||||
#[prost(message, required, tag="2")]
|
||||
pub config: EnclaveFrontendConfig,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveFrontendConfig {
|
||||
#[prost(uint32, required, tag="1")]
|
||||
pub replica_timeout_ticks: u32,
|
||||
#[prost(uint32, required, tag="2")]
|
||||
pub request_quote_ticks: u32,
|
||||
#[prost(uint32, required, tag="3")]
|
||||
pub min_connect_timeout_ticks: u32,
|
||||
#[prost(uint32, required, tag="4")]
|
||||
pub max_connect_timeout_ticks: u32,
|
||||
#[prost(uint32, required, tag="5")]
|
||||
pub pending_request_count: u32,
|
||||
#[prost(uint32, required, tag="6")]
|
||||
pub pending_request_ttl: u32,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SourcePartitionConfig {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub range: PartitionKeyRangePb,
|
||||
#[prost(bytes, repeated, tag="2")]
|
||||
pub node_ids: ::std::vec::Vec<std::vec::Vec<u8>>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct StartReplicaRequest {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub config: EnclaveReplicaConfig,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveReplicaConfig {
|
||||
#[prost(uint32, required, tag="1")]
|
||||
pub election_timeout_ticks: u32,
|
||||
#[prost(uint32, required, tag="2")]
|
||||
pub heartbeat_timeout_ticks: u32,
|
||||
#[prost(uint32, required, tag="3")]
|
||||
pub request_quote_ticks: u32,
|
||||
#[prost(uint32, required, tag="4")]
|
||||
pub min_connect_timeout_ticks: u32,
|
||||
#[prost(uint32, required, tag="5")]
|
||||
pub max_connect_timeout_ticks: u32,
|
||||
#[prost(uint32, required, tag="6")]
|
||||
pub attestation_expiry_ticks: u32,
|
||||
#[prost(uint32, required, tag="7")]
|
||||
pub replication_chunk_size: u32,
|
||||
#[prost(uint32, required, tag="8")]
|
||||
pub transfer_chunk_size: u32,
|
||||
#[prost(uint32, required, tag="10")]
|
||||
pub storage_page_cache_size: u32,
|
||||
#[prost(uint32, required, tag="13")]
|
||||
pub raft_log_index_page_cache_size: u32,
|
||||
#[prost(uint32, required, tag="14")]
|
||||
pub max_frontend_count: u32,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct StartReplicaGroupRequest {
|
||||
#[prost(bytes, repeated, tag="1")]
|
||||
pub peer_node_ids: ::std::vec::Vec<std::vec::Vec<u8>>,
|
||||
#[prost(message, required, tag="2")]
|
||||
pub config: EnclaveReplicaGroupConfig,
|
||||
#[prost(message, optional, tag="3")]
|
||||
pub source_partition: ::std::option::Option<SourcePartitionConfig>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveReplicaGroupConfig {
|
||||
#[prost(uint32, required, tag="1")]
|
||||
pub storage_size: u32,
|
||||
#[prost(uint64, required, tag="2")]
|
||||
pub raft_log_data_size: u64,
|
||||
#[prost(uint32, required, tag="3")]
|
||||
pub raft_log_index_size: u32,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct NewMessageSignal {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub node_id: std::vec::Vec<u8>,
|
||||
#[prost(bytes, required, tag="2")]
|
||||
pub data: std::vec::Vec<u8>,
|
||||
#[prost(bool, required, tag="3")]
|
||||
pub syn: bool,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TimerTickSignal {
|
||||
#[prost(fixed64, required, tag="1")]
|
||||
pub now_secs: u64,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SetFrontendConfigSignal {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub config: EnclaveFrontendConfig,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SetReplicaConfigSignal {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub config: EnclaveReplicaConfig,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ResetPeerSignal {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub peer_node_id: std::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SetVerboseLoggingSignal {
|
||||
#[prost(bool, required, tag="1")]
|
||||
pub verbose_logging: bool,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct GetQeInfoReply {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub mrenclave: std::vec::Vec<u8>,
|
||||
#[prost(uint64, required, tag="2")]
|
||||
pub flags: u64,
|
||||
#[prost(uint64, required, tag="3")]
|
||||
pub xfrm: u64,
|
||||
#[prost(uint32, required, tag="4")]
|
||||
pub misc_select: u32,
|
||||
#[prost(uint32, required, tag="5")]
|
||||
pub config_svn: u32,
|
||||
#[prost(bytes, required, tag="6")]
|
||||
pub config_id: std::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct GetQuoteReply {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub request_id: std::vec::Vec<u8>,
|
||||
#[prost(bytes, required, tag="2")]
|
||||
pub sgx_quote: std::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct GetAttestationReply {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub request_id: std::vec::Vec<u8>,
|
||||
#[prost(message, required, tag="2")]
|
||||
pub ias_report: IasReport,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct UntrustedTransactionRequest {
|
||||
#[prost(uint64, required, tag="1")]
|
||||
pub request_id: u64,
|
||||
#[prost(oneof="untrusted_transaction_request::Data", tags="2, 3")]
|
||||
pub data: ::std::option::Option<untrusted_transaction_request::Data>,
|
||||
}
|
||||
pub mod untrusted_transaction_request {
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Data {
|
||||
#[prost(message, tag="2")]
|
||||
CreateBackupRequest(super::CreateBackupRequest),
|
||||
#[prost(message, tag="3")]
|
||||
DeleteBackupRequest(super::DeleteBackupRequest),
|
||||
}
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct UntrustedXferRequest {
|
||||
#[prost(uint64, required, tag="1")]
|
||||
pub request_id: u64,
|
||||
#[prost(oneof="untrusted_xfer_request::Data", tags="2")]
|
||||
pub data: ::std::option::Option<untrusted_xfer_request::Data>,
|
||||
}
|
||||
pub mod untrusted_xfer_request {
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Data {
|
||||
#[prost(enumeration="super::XferControlCommand", tag="2")]
|
||||
XferControlCommand(i32),
|
||||
}
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct GetEnclaveStatusRequest {
|
||||
#[prost(bool, required, tag="1")]
|
||||
pub memory_status: bool,
|
||||
}
|
||||
//
|
||||
// enclave messages
|
||||
//
|
||||
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveMessageBatch {
|
||||
#[prost(message, repeated, tag="1")]
|
||||
pub messages: ::std::vec::Vec<EnclaveMessage>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveMessage {
|
||||
#[prost(oneof="enclave_message::Inner", tags="1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12")]
|
||||
pub inner: ::std::option::Option<enclave_message::Inner>,
|
||||
}
|
||||
pub mod enclave_message {
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Inner {
|
||||
#[prost(message, tag="1")]
|
||||
StartFrontendReply(super::StartFrontendReply),
|
||||
#[prost(message, tag="2")]
|
||||
StartReplicaReply(super::StartReplicaReply),
|
||||
#[prost(message, tag="3")]
|
||||
StartReplicaGroupReply(super::StartReplicaGroupReply),
|
||||
#[prost(message, tag="4")]
|
||||
UntrustedTransactionReply(super::UntrustedTransactionReply),
|
||||
#[prost(message, tag="5")]
|
||||
UntrustedXferReply(super::UntrustedXferReply),
|
||||
#[prost(message, tag="6")]
|
||||
GetEnclaveStatusReply(super::GetEnclaveStatusReply),
|
||||
#[prost(message, tag="7")]
|
||||
SendMessageRequest(super::SendMessageRequest),
|
||||
#[prost(message, tag="8")]
|
||||
GetQeInfoRequest(super::GetQeInfoRequest),
|
||||
#[prost(message, tag="9")]
|
||||
GetQuoteRequest(super::GetQuoteRequest),
|
||||
#[prost(message, tag="10")]
|
||||
GetAttestationRequest(super::GetAttestationRequest),
|
||||
#[prost(message, tag="11")]
|
||||
EnclaveLogSignal(super::EnclaveLogSignal),
|
||||
#[prost(message, tag="12")]
|
||||
EnclaveTransactionSignal(super::EnclaveTransactionSignal),
|
||||
}
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct StartFrontendReply {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub node_id: std::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct StartReplicaReply {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub node_id: std::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct StartReplicaGroupReply {
|
||||
#[prost(message, optional, tag="1")]
|
||||
pub service_id: ::std::option::Option<ServiceId>,
|
||||
#[prost(bytes, optional, tag="2")]
|
||||
pub group_id: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct GetEnclaveStatusReply {
|
||||
#[prost(oneof="get_enclave_status_reply::Inner", tags="1, 2")]
|
||||
pub inner: ::std::option::Option<get_enclave_status_reply::Inner>,
|
||||
}
|
||||
pub mod get_enclave_status_reply {
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Inner {
|
||||
#[prost(message, tag="1")]
|
||||
ReplicaStatus(super::EnclaveReplicaStatus),
|
||||
#[prost(message, tag="2")]
|
||||
FrontendStatus(super::EnclaveFrontendStatus),
|
||||
}
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SendMessageRequest {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub node_id: std::vec::Vec<u8>,
|
||||
#[prost(bytes, required, tag="2")]
|
||||
pub data: std::vec::Vec<u8>,
|
||||
#[prost(bool, required, tag="3")]
|
||||
pub syn: bool,
|
||||
#[prost(bytes, optional, tag="4")]
|
||||
pub debug_msg: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct GetQeInfoRequest {
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct GetQuoteRequest {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub request_id: std::vec::Vec<u8>,
|
||||
#[prost(bytes, required, tag="2")]
|
||||
pub sgx_report: std::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct GetAttestationRequest {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub request_id: std::vec::Vec<u8>,
|
||||
#[prost(bytes, required, tag="2")]
|
||||
pub sgx_quote: std::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct UntrustedTransactionReply {
|
||||
#[prost(uint64, required, tag="1")]
|
||||
pub request_id: u64,
|
||||
#[prost(oneof="untrusted_transaction_reply::Data", tags="2, 3")]
|
||||
pub data: ::std::option::Option<untrusted_transaction_reply::Data>,
|
||||
}
|
||||
pub mod untrusted_transaction_reply {
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Data {
|
||||
#[prost(message, tag="2")]
|
||||
CreateBackupReply(super::CreateBackupReply),
|
||||
#[prost(message, tag="3")]
|
||||
DeleteBackupReply(super::DeleteBackupReply),
|
||||
}
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct UntrustedXferReply {
|
||||
#[prost(uint64, required, tag="1")]
|
||||
pub request_id: u64,
|
||||
#[prost(enumeration="UntrustedXferReplyStatus", required, tag="2")]
|
||||
pub status: i32,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveLogSignal {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub message: std::vec::Vec<u8>,
|
||||
#[prost(bytes, required, tag="2")]
|
||||
pub module: std::vec::Vec<u8>,
|
||||
#[prost(bytes, required, tag="3")]
|
||||
pub file: std::vec::Vec<u8>,
|
||||
#[prost(uint32, required, tag="4")]
|
||||
pub line: u32,
|
||||
#[prost(enumeration="EnclaveLogLevel", required, tag="5")]
|
||||
pub level: i32,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveTransactionSignal {
|
||||
#[prost(uint64, required, tag="1")]
|
||||
pub log_index: u64,
|
||||
#[prost(oneof="enclave_transaction_signal::Transaction", tags="2, 3, 4, 5, 6, 7, 8, 9, 10")]
|
||||
pub transaction: ::std::option::Option<enclave_transaction_signal::Transaction>,
|
||||
}
|
||||
pub mod enclave_transaction_signal {
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Transaction {
|
||||
#[prost(message, tag="2")]
|
||||
FrontendRequest(super::EnclaveFrontendRequestTransaction),
|
||||
#[prost(message, tag="3")]
|
||||
StartXfer(super::EnclaveStartXferTransaction),
|
||||
#[prost(message, tag="4")]
|
||||
SetSid(super::EnclaveSetSidTransaction),
|
||||
#[prost(message, tag="5")]
|
||||
RemoveChunk(super::EnclaveRemoveChunkTransaction),
|
||||
#[prost(message, tag="6")]
|
||||
ApplyChunk(super::EnclaveApplyChunkTransaction),
|
||||
#[prost(message, tag="7")]
|
||||
PauseXfer(super::EnclavePauseXferTransaction),
|
||||
#[prost(message, tag="8")]
|
||||
ResumeXfer(super::EnclaveResumeXferTransaction),
|
||||
#[prost(message, tag="9")]
|
||||
FinishXfer(super::EnclaveFinishXferTransaction),
|
||||
#[prost(message, tag="10")]
|
||||
SetTime(super::EnclaveSetTimeTransaction),
|
||||
}
|
||||
}
|
||||
//
|
||||
// enclave transactions
|
||||
//
|
||||
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveFrontendRequestTransaction {
|
||||
#[prost(oneof="enclave_frontend_request_transaction::Transaction", tags="1, 2, 3, 4, 5, 6, 7, 8")]
|
||||
pub transaction: ::std::option::Option<enclave_frontend_request_transaction::Transaction>,
|
||||
}
|
||||
pub mod enclave_frontend_request_transaction {
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Transaction {
|
||||
#[prost(message, tag="1")]
|
||||
Create(super::EnclaveCreateBackupTransaction),
|
||||
#[prost(message, tag="2")]
|
||||
Backup(super::EnclaveBackupTransaction),
|
||||
#[prost(message, tag="3")]
|
||||
Restore(super::EnclaveRestoreTransaction),
|
||||
#[prost(message, tag="4")]
|
||||
Delete(super::EnclaveDeleteBackupTransaction),
|
||||
#[prost(message, tag="5")]
|
||||
XferInProgress(super::EnclaveTransactionErrorXferInProgress),
|
||||
#[prost(message, tag="6")]
|
||||
WrongPartition(super::EnclaveTransactionErrorWrongPartition),
|
||||
#[prost(message, tag="7")]
|
||||
InvalidRequest(super::EnclaveTransactionErrorInvalidRequest),
|
||||
#[prost(message, tag="8")]
|
||||
InternalError(super::EnclaveTransactionErrorInternalError),
|
||||
}
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveCreateBackupTransaction {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub backup_id: BackupId,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveBackupTransaction {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub backup_id: BackupId,
|
||||
#[prost(enumeration="super::kbupd_client::backup_response::Status", required, tag="2")]
|
||||
pub status: i32,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveRestoreTransaction {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub backup_id: BackupId,
|
||||
#[prost(enumeration="super::kbupd_client::restore_response::Status", required, tag="2")]
|
||||
pub status: i32,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveDeleteBackupTransaction {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub backup_id: BackupId,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveTransactionErrorXferInProgress {
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveTransactionErrorWrongPartition {
|
||||
#[prost(bool, required, tag="1")]
|
||||
pub new_partition_unknown: bool,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveTransactionErrorInvalidRequest {
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveTransactionErrorInternalError {
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveStartXferTransaction {
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveSetSidTransaction {
|
||||
#[prost(message, optional, tag="1")]
|
||||
pub service_id: ::std::option::Option<ServiceId>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveRemoveChunkTransaction {
|
||||
#[prost(message, optional, tag="1")]
|
||||
pub chunk_range: ::std::option::Option<PartitionKeyRangePb>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveApplyChunkTransaction {
|
||||
#[prost(message, optional, tag="1")]
|
||||
pub chunk_range: ::std::option::Option<PartitionKeyRangePb>,
|
||||
#[prost(message, repeated, tag="2")]
|
||||
pub chunk_ids: ::std::vec::Vec<BackupId>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclavePauseXferTransaction {
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveResumeXferTransaction {
|
||||
#[prost(message, optional, tag="1")]
|
||||
pub chunk_range: ::std::option::Option<PartitionKeyRangePb>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveFinishXferTransaction {
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveSetTimeTransaction {
|
||||
#[prost(uint64, optional, tag="1")]
|
||||
pub now_secs: ::std::option::Option<u64>,
|
||||
}
|
||||
//
|
||||
// enclave status
|
||||
//
|
||||
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveMemoryStatus {
|
||||
#[prost(uint32, required, tag="1")]
|
||||
pub footprint_bytes: u32,
|
||||
#[prost(uint32, required, tag="2")]
|
||||
pub used_bytes: u32,
|
||||
#[prost(uint32, required, tag="3")]
|
||||
pub free_chunks: u32,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveReplicaStatus {
|
||||
#[prost(message, optional, tag="1")]
|
||||
pub memory_status: ::std::option::Option<EnclaveMemoryStatus>,
|
||||
#[prost(message, optional, tag="2")]
|
||||
pub partition: ::std::option::Option<EnclaveReplicaPartitionStatus>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveReplicaPartitionStatus {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub group_id: std::vec::Vec<u8>,
|
||||
#[prost(bytes, optional, tag="2")]
|
||||
pub service_id: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
#[prost(message, optional, tag="3")]
|
||||
pub range: ::std::option::Option<PartitionKeyRangePb>,
|
||||
#[prost(message, repeated, tag="4")]
|
||||
pub peers: ::std::vec::Vec<EnclavePeerStatus>,
|
||||
#[prost(message, required, tag="5")]
|
||||
pub min_attestation: AttestationParameters,
|
||||
#[prost(bool, required, tag="6")]
|
||||
pub is_leader: bool,
|
||||
#[prost(uint64, required, tag="7")]
|
||||
pub current_term: u64,
|
||||
#[prost(uint64, required, tag="8")]
|
||||
pub prev_log_index: u64,
|
||||
#[prost(uint64, required, tag="9")]
|
||||
pub last_applied_index: u64,
|
||||
#[prost(uint64, required, tag="10")]
|
||||
pub commit_index: u64,
|
||||
#[prost(uint64, required, tag="11")]
|
||||
pub last_log_index: u64,
|
||||
#[prost(uint64, required, tag="12")]
|
||||
pub last_log_term: u64,
|
||||
#[prost(uint64, required, tag="13")]
|
||||
pub log_data_length: u64,
|
||||
#[prost(uint64, required, tag="14")]
|
||||
pub backup_count: u64,
|
||||
#[prost(oneof="enclave_replica_partition_status::XferStatus", tags="15, 16")]
|
||||
pub xfer_status: ::std::option::Option<enclave_replica_partition_status::XferStatus>,
|
||||
}
|
||||
pub mod enclave_replica_partition_status {
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum XferStatus {
|
||||
#[prost(message, tag="15")]
|
||||
IncomingXferStatus(super::EnclaveIncomingXferStatus),
|
||||
#[prost(message, tag="16")]
|
||||
OutgoingXferStatus(super::EnclaveOutgoingXferStatus),
|
||||
}
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclavePeerStatus {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub node_id: std::vec::Vec<u8>,
|
||||
#[prost(message, optional, tag="2")]
|
||||
pub attestation: ::std::option::Option<AttestationParameters>,
|
||||
#[prost(message, optional, tag="3")]
|
||||
pub replication_status: ::std::option::Option<EnclavePeerReplicationStatus>,
|
||||
#[prost(bool, required, tag="4")]
|
||||
pub is_leader: bool,
|
||||
#[prost(uint64, required, tag="5")]
|
||||
pub inflight_requests: u64,
|
||||
#[prost(uint64, required, tag="6")]
|
||||
pub unsent_requests: u64,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclavePeerReplicationStatus {
|
||||
#[prost(uint64, required, tag="1")]
|
||||
pub next_index: u64,
|
||||
#[prost(uint64, required, tag="2")]
|
||||
pub match_index: u64,
|
||||
#[prost(uint64, optional, tag="3")]
|
||||
pub inflight_index: ::std::option::Option<u64>,
|
||||
#[prost(bool, required, tag="4")]
|
||||
pub probing: bool,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveIncomingXferStatus {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub desired_range: PartitionKeyRangePb,
|
||||
#[prost(message, repeated, tag="2")]
|
||||
pub nodes: ::std::vec::Vec<EnclavePeerStatus>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveOutgoingXferStatus {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub group_id: std::vec::Vec<u8>,
|
||||
#[prost(message, required, tag="2")]
|
||||
pub full_xfer_range: PartitionKeyRangePb,
|
||||
#[prost(message, optional, tag="3")]
|
||||
pub current_chunk_range: ::std::option::Option<PartitionKeyRangePb>,
|
||||
#[prost(bool, required, tag="4")]
|
||||
pub paused: bool,
|
||||
#[prost(message, optional, tag="5")]
|
||||
pub min_attestation: ::std::option::Option<AttestationParameters>,
|
||||
#[prost(message, repeated, tag="6")]
|
||||
pub nodes: ::std::vec::Vec<EnclavePeerStatus>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveFrontendStatus {
|
||||
#[prost(message, optional, tag="1")]
|
||||
pub memory_status: ::std::option::Option<EnclaveMemoryStatus>,
|
||||
#[prost(message, repeated, tag="2")]
|
||||
pub partitions: ::std::vec::Vec<EnclaveFrontendPartitionStatus>,
|
||||
#[prost(message, repeated, tag="3")]
|
||||
pub ranges: ::std::vec::Vec<EnclaveFrontendRangeStatus>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveFrontendPartitionStatus {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub group_id: std::vec::Vec<u8>,
|
||||
#[prost(message, repeated, tag="2")]
|
||||
pub nodes: ::std::vec::Vec<EnclavePeerStatus>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveFrontendRangeStatus {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub range: PartitionKeyRangePb,
|
||||
#[prost(bytes, required, tag="2")]
|
||||
pub group_id: std::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
||||
#[repr(i32)]
|
||||
pub enum XferControlCommand {
|
||||
Start = 1,
|
||||
Finish = 2,
|
||||
Cancel = 3,
|
||||
Pause = 4,
|
||||
Resume = 5,
|
||||
}
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
||||
#[repr(i32)]
|
||||
pub enum UntrustedXferReplyStatus {
|
||||
Unknown = 0,
|
||||
Ok = 1,
|
||||
NotLeader = 2,
|
||||
InvalidState = 3,
|
||||
}
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
||||
#[repr(i32)]
|
||||
pub enum EnclaveLogLevel {
|
||||
Error = 0,
|
||||
Warn = 1,
|
||||
Info = 2,
|
||||
Debug = 3,
|
||||
}
|
||||
108
enclave/kbupd_enclave/src/protobufs/kbupd_client.rs
Normal file
108
enclave/kbupd_enclave/src/protobufs/kbupd_client.rs
Normal file
@ -0,0 +1,108 @@
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Request {
|
||||
#[prost(message, optional, tag="1")]
|
||||
pub backup: ::std::option::Option<BackupRequest>,
|
||||
#[prost(message, optional, tag="2")]
|
||||
pub restore: ::std::option::Option<RestoreRequest>,
|
||||
#[prost(message, optional, tag="3")]
|
||||
pub delete: ::std::option::Option<DeleteRequest>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct Response {
|
||||
#[prost(message, optional, tag="1")]
|
||||
pub backup: ::std::option::Option<BackupResponse>,
|
||||
#[prost(message, optional, tag="2")]
|
||||
pub restore: ::std::option::Option<RestoreResponse>,
|
||||
#[prost(message, optional, tag="3")]
|
||||
pub delete: ::std::option::Option<DeleteResponse>,
|
||||
}
|
||||
//
|
||||
// backup
|
||||
//
|
||||
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct BackupRequest {
|
||||
#[prost(bytes, optional, tag="1")]
|
||||
pub service_id: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
#[prost(bytes, optional, tag="2")]
|
||||
pub backup_id: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
#[prost(bytes, optional, tag="3")]
|
||||
pub nonce: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
#[prost(uint64, optional, tag="4")]
|
||||
pub valid_from: ::std::option::Option<u64>,
|
||||
#[prost(bytes, optional, tag="5")]
|
||||
pub data: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
#[prost(bytes, optional, tag="6")]
|
||||
pub pin: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
#[prost(uint32, optional, tag="7")]
|
||||
pub tries: ::std::option::Option<u32>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct BackupResponse {
|
||||
#[prost(enumeration="backup_response::Status", optional, tag="1")]
|
||||
pub status: ::std::option::Option<i32>,
|
||||
#[prost(bytes, optional, tag="2")]
|
||||
pub nonce: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
}
|
||||
pub mod backup_response {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
||||
#[repr(i32)]
|
||||
pub enum Status {
|
||||
Ok = 1,
|
||||
AlreadyExists = 2,
|
||||
NotYetValid = 3,
|
||||
}
|
||||
}
|
||||
//
|
||||
// restore
|
||||
//
|
||||
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct RestoreRequest {
|
||||
#[prost(bytes, optional, tag="1")]
|
||||
pub service_id: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
#[prost(bytes, optional, tag="2")]
|
||||
pub backup_id: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
#[prost(bytes, optional, tag="3")]
|
||||
pub nonce: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
#[prost(uint64, optional, tag="4")]
|
||||
pub valid_from: ::std::option::Option<u64>,
|
||||
#[prost(bytes, optional, tag="5")]
|
||||
pub pin: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct RestoreResponse {
|
||||
#[prost(enumeration="restore_response::Status", optional, tag="1")]
|
||||
pub status: ::std::option::Option<i32>,
|
||||
#[prost(bytes, optional, tag="2")]
|
||||
pub nonce: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
#[prost(bytes, optional, tag="3")]
|
||||
pub data: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
#[prost(uint32, optional, tag="4")]
|
||||
pub tries: ::std::option::Option<u32>,
|
||||
}
|
||||
pub mod restore_response {
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
||||
#[repr(i32)]
|
||||
pub enum Status {
|
||||
Ok = 1,
|
||||
NonceMismatch = 2,
|
||||
NotYetValid = 3,
|
||||
Missing = 4,
|
||||
PinMismatch = 5,
|
||||
}
|
||||
}
|
||||
//
|
||||
// delete
|
||||
//
|
||||
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct DeleteRequest {
|
||||
#[prost(bytes, optional, tag="1")]
|
||||
pub service_id: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
#[prost(bytes, optional, tag="2")]
|
||||
pub backup_id: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct DeleteResponse {
|
||||
}
|
||||
431
enclave/kbupd_enclave/src/protobufs/kbupd_enclave.rs
Normal file
431
enclave/kbupd_enclave/src/protobufs/kbupd_enclave.rs
Normal file
@ -0,0 +1,431 @@
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SecretBytes {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub data: std::vec::Vec<u8>,
|
||||
}
|
||||
//
|
||||
// transactions
|
||||
//
|
||||
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TransactionData {
|
||||
#[prost(oneof="transaction_data::Inner", tags="1, 2, 3, 4, 5, 6, 7, 8, 9")]
|
||||
pub inner: ::std::option::Option<transaction_data::Inner>,
|
||||
}
|
||||
pub mod transaction_data {
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Inner {
|
||||
#[prost(message, tag="1")]
|
||||
FrontendRequest(super::FrontendRequestTransaction),
|
||||
#[prost(message, tag="2")]
|
||||
StartXfer(super::StartXferTransaction),
|
||||
#[prost(message, tag="3")]
|
||||
SetSid(super::SetSidTransaction),
|
||||
#[prost(message, tag="4")]
|
||||
RemoveChunk(super::RemoveChunkTransaction),
|
||||
#[prost(message, tag="5")]
|
||||
ApplyChunk(super::ApplyChunkTransaction),
|
||||
#[prost(message, tag="6")]
|
||||
PauseXfer(super::PauseXferTransaction),
|
||||
#[prost(message, tag="7")]
|
||||
ResumeXfer(super::ResumeXferTransaction),
|
||||
#[prost(message, tag="8")]
|
||||
FinishXfer(super::FinishXferTransaction),
|
||||
#[prost(message, tag="9")]
|
||||
SetTime(super::SetTimeTransaction),
|
||||
}
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct FrontendRequestTransaction {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub from_node_id: std::vec::Vec<u8>,
|
||||
#[prost(uint64, required, tag="2")]
|
||||
pub request_id: u64,
|
||||
#[prost(oneof="frontend_request_transaction::Transaction", tags="3, 4, 5, 6")]
|
||||
pub transaction: ::std::option::Option<frontend_request_transaction::Transaction>,
|
||||
}
|
||||
pub mod frontend_request_transaction {
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Transaction {
|
||||
#[prost(message, tag="3")]
|
||||
Create(super::CreateBackupTransaction),
|
||||
#[prost(message, tag="4")]
|
||||
Backup(super::BackupTransaction),
|
||||
#[prost(message, tag="5")]
|
||||
Restore(super::RestoreTransaction),
|
||||
#[prost(message, tag="6")]
|
||||
Delete(super::DeleteBackupTransaction),
|
||||
}
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct CreateBackupTransaction {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub backup_id: super::kbupd::BackupId,
|
||||
#[prost(bytes, required, tag="2")]
|
||||
pub new_creation_nonce: std::vec::Vec<u8>,
|
||||
#[prost(bytes, required, tag="3")]
|
||||
pub new_nonce: std::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct BackupTransaction {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub backup_id: super::kbupd::BackupId,
|
||||
#[prost(bytes, required, tag="2")]
|
||||
pub old_nonce: std::vec::Vec<u8>,
|
||||
#[prost(bytes, required, tag="3")]
|
||||
pub new_creation_nonce: std::vec::Vec<u8>,
|
||||
#[prost(bytes, required, tag="4")]
|
||||
pub new_nonce: std::vec::Vec<u8>,
|
||||
#[prost(message, required, tag="5")]
|
||||
pub data: SecretBytes,
|
||||
#[prost(message, required, tag="6")]
|
||||
pub pin: SecretBytes,
|
||||
#[prost(uint32, required, tag="7")]
|
||||
pub tries: u32,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct RestoreTransaction {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub backup_id: super::kbupd::BackupId,
|
||||
#[prost(bytes, required, tag="2")]
|
||||
pub creation_nonce: std::vec::Vec<u8>,
|
||||
#[prost(bytes, required, tag="3")]
|
||||
pub old_nonce: std::vec::Vec<u8>,
|
||||
#[prost(bytes, required, tag="4")]
|
||||
pub new_nonce: std::vec::Vec<u8>,
|
||||
#[prost(message, required, tag="5")]
|
||||
pub pin: SecretBytes,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct DeleteBackupTransaction {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub backup_id: super::kbupd::BackupId,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct StartXferTransaction {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub from_node_id: std::vec::Vec<u8>,
|
||||
#[prost(message, required, tag="2")]
|
||||
pub xfer_request: XferRequest,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SetSidTransaction {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub from_node_id: std::vec::Vec<u8>,
|
||||
#[prost(message, required, tag="2")]
|
||||
pub service_id: super::kbupd::ServiceId,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct RemoveChunkTransaction {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub from_node_id: std::vec::Vec<u8>,
|
||||
#[prost(message, required, tag="2")]
|
||||
pub xfer_chunk_reply: XferChunkReply,
|
||||
#[prost(message, required, tag="3")]
|
||||
pub chunk_last: super::kbupd::BackupId,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ApplyChunkTransaction {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub from_node_id: std::vec::Vec<u8>,
|
||||
#[prost(message, required, tag="2")]
|
||||
pub xfer_chunk_request: XferChunkRequest,
|
||||
#[prost(message, required, tag="3")]
|
||||
pub xfer_chunk_reply: XferChunkReply,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct PauseXferTransaction {
|
||||
#[prost(uint64, required, tag="1")]
|
||||
pub request_id: u64,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ResumeXferTransaction {
|
||||
#[prost(uint64, required, tag="1")]
|
||||
pub request_id: u64,
|
||||
#[prost(message, required, tag="2")]
|
||||
pub chunk_last: super::kbupd::BackupId,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct FinishXferTransaction {
|
||||
#[prost(uint64, required, tag="1")]
|
||||
pub request_id: u64,
|
||||
#[prost(bool, required, tag="2")]
|
||||
pub force: bool,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct SetTimeTransaction {
|
||||
#[prost(uint64, required, tag="1")]
|
||||
pub now_secs: u64,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct PeerConnectRequest {
|
||||
#[prost(enumeration="NodeType", required, tag="1")]
|
||||
pub node_type: i32,
|
||||
#[prost(message, optional, tag="2")]
|
||||
pub ias_report: ::std::option::Option<super::kbupd::IasReport>,
|
||||
#[prost(bytes, required, tag="3")]
|
||||
pub noise_data: std::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct PeerConnectReply {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub sgx_quote: std::vec::Vec<u8>,
|
||||
#[prost(bytes, required, tag="2")]
|
||||
pub noise_data: std::vec::Vec<u8>,
|
||||
}
|
||||
//
|
||||
// enclave-to-enclave requests
|
||||
//
|
||||
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveGetQuoteRequest {
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct EnclaveGetQuoteReply {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub sgx_quote: std::vec::Vec<u8>,
|
||||
}
|
||||
//
|
||||
// frontend to replica
|
||||
//
|
||||
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct FrontendToReplicaMessage {
|
||||
#[prost(oneof="frontend_to_replica_message::Inner", tags="1, 2")]
|
||||
pub inner: ::std::option::Option<frontend_to_replica_message::Inner>,
|
||||
}
|
||||
pub mod frontend_to_replica_message {
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Inner {
|
||||
#[prost(message, tag="1")]
|
||||
TransactionRequest(super::TransactionRequest),
|
||||
#[prost(message, tag="2")]
|
||||
EnclaveGetQuoteRequest(super::EnclaveGetQuoteRequest),
|
||||
}
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TransactionRequest {
|
||||
#[prost(uint64, required, tag="1")]
|
||||
pub request_id: u64,
|
||||
#[prost(oneof="transaction_request::Data", tags="2, 3, 4, 5")]
|
||||
pub data: ::std::option::Option<transaction_request::Data>,
|
||||
}
|
||||
pub mod transaction_request {
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Data {
|
||||
#[prost(message, tag="2")]
|
||||
Create(super::super::kbupd::CreateBackupRequest),
|
||||
#[prost(message, tag="3")]
|
||||
Backup(super::BackupTransactionRequest),
|
||||
#[prost(message, tag="4")]
|
||||
Restore(super::RestoreTransactionRequest),
|
||||
#[prost(message, tag="5")]
|
||||
Delete(super::DeleteTransactionRequest),
|
||||
}
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct BackupTransactionRequest {
|
||||
#[prost(bytes, optional, tag="1")]
|
||||
pub service_id: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
#[prost(message, required, tag="2")]
|
||||
pub backup_id: super::kbupd::BackupId,
|
||||
#[prost(bytes, required, tag="3")]
|
||||
pub nonce: std::vec::Vec<u8>,
|
||||
#[prost(uint64, required, tag="4")]
|
||||
pub valid_from: u64,
|
||||
#[prost(message, required, tag="5")]
|
||||
pub data: SecretBytes,
|
||||
#[prost(message, required, tag="6")]
|
||||
pub pin: SecretBytes,
|
||||
#[prost(uint32, required, tag="7")]
|
||||
pub tries: u32,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct RestoreTransactionRequest {
|
||||
#[prost(bytes, optional, tag="1")]
|
||||
pub service_id: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
#[prost(message, required, tag="2")]
|
||||
pub backup_id: super::kbupd::BackupId,
|
||||
#[prost(bytes, required, tag="3")]
|
||||
pub nonce: std::vec::Vec<u8>,
|
||||
#[prost(uint64, required, tag="4")]
|
||||
pub valid_from: u64,
|
||||
#[prost(message, required, tag="5")]
|
||||
pub pin: SecretBytes,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct DeleteTransactionRequest {
|
||||
#[prost(bytes, optional, tag="1")]
|
||||
pub service_id: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
#[prost(message, required, tag="2")]
|
||||
pub backup_id: super::kbupd::BackupId,
|
||||
}
|
||||
//
|
||||
// replica to frontend
|
||||
//
|
||||
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ReplicaToFrontendMessage {
|
||||
#[prost(oneof="replica_to_frontend_message::Inner", tags="1, 2")]
|
||||
pub inner: ::std::option::Option<replica_to_frontend_message::Inner>,
|
||||
}
|
||||
pub mod replica_to_frontend_message {
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Inner {
|
||||
#[prost(message, tag="1")]
|
||||
TransactionReply(super::TransactionReply),
|
||||
#[prost(message, tag="2")]
|
||||
EnclaveGetQuoteReply(super::EnclaveGetQuoteReply),
|
||||
}
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TransactionReply {
|
||||
#[prost(uint64, required, tag="1")]
|
||||
pub request_id: u64,
|
||||
#[prost(oneof="transaction_reply::Data", tags="2, 3, 4, 5, 6, 7, 8, 9, 10")]
|
||||
pub data: ::std::option::Option<transaction_reply::Data>,
|
||||
}
|
||||
pub mod transaction_reply {
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Data {
|
||||
#[prost(message, tag="2")]
|
||||
ClientResponse(super::super::kbupd_client::Response),
|
||||
#[prost(message, tag="3")]
|
||||
CreateBackupReply(super::super::kbupd::CreateBackupReply),
|
||||
#[prost(message, tag="4")]
|
||||
DeleteBackupReply(super::super::kbupd::DeleteBackupReply),
|
||||
#[prost(message, tag="5")]
|
||||
NotLeader(super::TransactionErrorNotLeader),
|
||||
#[prost(message, tag="6")]
|
||||
WrongPartition(super::TransactionErrorWrongPartition),
|
||||
#[prost(message, tag="7")]
|
||||
ServiceIdMismatch(super::TransactionErrorServiceIdMismatch),
|
||||
#[prost(message, tag="8")]
|
||||
XferInProgress(super::TransactionErrorXferInProgress),
|
||||
#[prost(message, tag="9")]
|
||||
InvalidRequest(super::TransactionErrorInvalidRequest),
|
||||
#[prost(message, tag="10")]
|
||||
InternalError(super::TransactionErrorInternalError),
|
||||
}
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TransactionErrorNotLeader {
|
||||
#[prost(bytes, optional, tag="1")]
|
||||
pub leader_node_id: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
#[prost(message, required, tag="2")]
|
||||
pub term: super::raft::TermId,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TransactionErrorWrongPartition {
|
||||
#[prost(message, optional, tag="1")]
|
||||
pub range: ::std::option::Option<super::kbupd::PartitionKeyRangePb>,
|
||||
#[prost(message, optional, tag="2")]
|
||||
pub new_partition: ::std::option::Option<super::kbupd::PartitionConfig>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TransactionErrorServiceIdMismatch {
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TransactionErrorXferInProgress {
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TransactionErrorInvalidRequest {
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TransactionErrorInternalError {
|
||||
}
|
||||
//
|
||||
// replica to replica
|
||||
//
|
||||
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct ReplicaToReplicaMessage {
|
||||
#[prost(oneof="replica_to_replica_message::Inner", tags="1, 2, 8, 9, 3, 4, 5, 6, 7")]
|
||||
pub inner: ::std::option::Option<replica_to_replica_message::Inner>,
|
||||
}
|
||||
pub mod replica_to_replica_message {
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Inner {
|
||||
#[prost(message, tag="1")]
|
||||
RaftMessage(super::super::raft::RaftMessage),
|
||||
#[prost(message, tag="2")]
|
||||
CreateRaftGroupRequest(super::CreateRaftGroupRequest),
|
||||
#[prost(message, tag="8")]
|
||||
EnclaveGetQuoteRequest(super::EnclaveGetQuoteRequest),
|
||||
#[prost(message, tag="9")]
|
||||
EnclaveGetQuoteReply(super::EnclaveGetQuoteReply),
|
||||
#[prost(message, tag="3")]
|
||||
XferRequest(super::XferRequest),
|
||||
#[prost(message, tag="4")]
|
||||
XferReply(super::XferReply),
|
||||
#[prost(message, tag="5")]
|
||||
XferChunkRequest(super::XferChunkRequest),
|
||||
#[prost(message, tag="6")]
|
||||
XferChunkReply(super::XferChunkReply),
|
||||
#[prost(message, tag="7")]
|
||||
XferErrorNotLeader(super::XferErrorNotLeader),
|
||||
}
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct CreateRaftGroupRequest {
|
||||
#[prost(message, optional, tag="1")]
|
||||
pub service_id: ::std::option::Option<super::kbupd::ServiceId>,
|
||||
#[prost(message, required, tag="2")]
|
||||
pub group_id: super::raft::RaftGroupId,
|
||||
#[prost(bytes, repeated, tag="3")]
|
||||
pub node_ids: ::std::vec::Vec<std::vec::Vec<u8>>,
|
||||
#[prost(message, required, tag="4")]
|
||||
pub config: super::kbupd::EnclaveReplicaGroupConfig,
|
||||
#[prost(message, optional, tag="5")]
|
||||
pub source_partition: ::std::option::Option<super::kbupd::SourcePartitionConfig>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct XferRequest {
|
||||
#[prost(uint32, required, tag="1")]
|
||||
pub chunk_size: u32,
|
||||
#[prost(message, required, tag="2")]
|
||||
pub full_range: super::kbupd::PartitionKeyRangePb,
|
||||
#[prost(bytes, repeated, tag="3")]
|
||||
pub node_ids: ::std::vec::Vec<std::vec::Vec<u8>>,
|
||||
#[prost(message, required, tag="4")]
|
||||
pub group_id: super::raft::RaftGroupId,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct XferReply {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub service: super::kbupd::ServiceId,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct XferChunkRequest {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub data: SecretBytes,
|
||||
#[prost(message, required, tag="2")]
|
||||
pub chunk_range: super::kbupd::PartitionKeyRangePb,
|
||||
#[prost(message, required, tag="3")]
|
||||
pub min_attestation: super::kbupd::AttestationParameters,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct XferChunkReply {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub new_last: super::kbupd::BackupId,
|
||||
#[prost(uint32, required, tag="2")]
|
||||
pub chunk_size: u32,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct XferErrorNotLeader {
|
||||
#[prost(bytes, optional, tag="1")]
|
||||
pub leader_node_id: ::std::option::Option<std::vec::Vec<u8>>,
|
||||
#[prost(message, required, tag="2")]
|
||||
pub term: super::raft::TermId,
|
||||
}
|
||||
//
|
||||
// remote enclave handshake
|
||||
//
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, ::prost::Enumeration)]
|
||||
#[repr(i32)]
|
||||
pub enum NodeType {
|
||||
None = 0,
|
||||
Frontend = 1,
|
||||
Replica = 2,
|
||||
}
|
||||
4
enclave/kbupd_enclave/src/protobufs/mod.rs
Normal file
4
enclave/kbupd_enclave/src/protobufs/mod.rs
Normal file
@ -0,0 +1,4 @@
|
||||
pub mod kbupd;
|
||||
pub mod kbupd_client;
|
||||
pub mod kbupd_enclave;
|
||||
pub mod raft;
|
||||
76
enclave/kbupd_enclave/src/protobufs/raft.rs
Normal file
76
enclave/kbupd_enclave/src/protobufs/raft.rs
Normal file
@ -0,0 +1,76 @@
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct RaftMessage {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub group: RaftGroupId,
|
||||
#[prost(message, required, tag="2")]
|
||||
pub term: TermId,
|
||||
#[prost(oneof="raft_message::Inner", tags="3, 4, 5, 6")]
|
||||
pub inner: ::std::option::Option<raft_message::Inner>,
|
||||
}
|
||||
pub mod raft_message {
|
||||
#[derive(Clone, PartialEq, ::prost::Oneof)]
|
||||
pub enum Inner {
|
||||
#[prost(message, tag="3")]
|
||||
VoteRequest(super::VoteRequest),
|
||||
#[prost(message, tag="4")]
|
||||
VoteResponse(super::VoteResponse),
|
||||
#[prost(message, tag="5")]
|
||||
AppendRequest(super::AppendRequest),
|
||||
#[prost(message, tag="6")]
|
||||
AppendResponse(super::AppendResponse),
|
||||
}
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct VoteRequest {
|
||||
#[prost(message, required, tag="2")]
|
||||
pub last_log_idx: LogIdx,
|
||||
#[prost(message, required, tag="3")]
|
||||
pub last_log_term: TermId,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct VoteResponse {
|
||||
#[prost(bool, required, tag="2")]
|
||||
pub vote_granted: bool,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct AppendRequest {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub prev_log_idx: LogIdx,
|
||||
#[prost(message, required, tag="2")]
|
||||
pub prev_log_term: TermId,
|
||||
#[prost(message, required, tag="3")]
|
||||
pub leader_commit: LogIdx,
|
||||
#[prost(message, repeated, tag="4")]
|
||||
pub entries: ::std::vec::Vec<LogEntry>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct AppendResponse {
|
||||
#[prost(bool, required, tag="1")]
|
||||
pub success: bool,
|
||||
#[prost(message, required, tag="2")]
|
||||
pub match_idx: LogIdx,
|
||||
#[prost(message, required, tag="3")]
|
||||
pub last_log_idx: LogIdx,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct LogEntry {
|
||||
#[prost(message, required, tag="1")]
|
||||
pub term: TermId,
|
||||
#[prost(bytes, required, tag="2")]
|
||||
pub data: std::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct RaftGroupId {
|
||||
#[prost(bytes, required, tag="1")]
|
||||
pub id: std::vec::Vec<u8>,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct TermId {
|
||||
#[prost(uint64, required, tag="1")]
|
||||
pub id: u64,
|
||||
}
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct LogIdx {
|
||||
#[prost(uint64, required, tag="1")]
|
||||
pub id: u64,
|
||||
}
|
||||
210
enclave/kbupd_enclave/src/protobufs_impl/kbupd.rs
Normal file
210
enclave/kbupd_enclave/src/protobufs_impl/kbupd.rs
Normal file
@ -0,0 +1,210 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
use std::cmp::*;
|
||||
use std::fmt;
|
||||
use std::ops::*;
|
||||
use crate::prelude::*;
|
||||
|
||||
|
||||
use crate::util::*;
|
||||
use crate::protobufs::kbupd::*;
|
||||
use crate::protobufs::kbupd_enclave;
|
||||
use crate::protobufs::kbupd_client;
|
||||
|
||||
//
|
||||
// ServiceId impls
|
||||
//
|
||||
|
||||
impl fmt::Display for ServiceId {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self { id } = self;
|
||||
write!(fmt, "{}", ToHex(id))
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// BackupId impls
|
||||
//
|
||||
|
||||
impl BackupId {
|
||||
pub const LENGTH: usize = 32;
|
||||
pub fn valid_len() -> u32 {
|
||||
32
|
||||
}
|
||||
|
||||
pub fn try_from_slice<T>(slice: T) -> Result<Self, ()>
|
||||
where T: AsRef<[u8]>,
|
||||
{
|
||||
let slice: &[u8] = slice.as_ref();
|
||||
if slice.len() == Self::LENGTH {
|
||||
let id = slice.to_vec();
|
||||
Ok(Self { id })
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
pub fn try_to_array(&self) -> Result<[u8; Self::LENGTH], ()> {
|
||||
let mut array = [0; Self::LENGTH];
|
||||
if self.id.len() == array.len() {
|
||||
array.copy_from_slice(&self.id);
|
||||
Ok(array)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; 32]> for BackupId {
|
||||
fn from(from: [u8; 32]) -> Self {
|
||||
Self { id: from.to_vec() }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for BackupId {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.id
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for BackupId {
|
||||
type Target = Vec<u8>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.id
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for BackupId {}
|
||||
impl PartialOrd for BackupId {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { Some(self.cmp(other)) }
|
||||
}
|
||||
impl Ord for BackupId {
|
||||
fn cmp(&self, other: &Self) -> Ordering { self.id.cmp(&other.id) }
|
||||
}
|
||||
|
||||
impl fmt::Display for BackupId {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self { id } = self;
|
||||
write!(fmt, "{}", ToHex(id))
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// PartitionKeyRangePB
|
||||
//
|
||||
|
||||
impl fmt::Display for PartitionKeyRangePb {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self { first, last } = self;
|
||||
write!(fmt, "{}-{}", ToHex(first), ToHex(last))
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// UntrustedTransactionRequest
|
||||
//
|
||||
|
||||
impl fmt::Display for UntrustedTransactionRequest {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(self, fmt)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// EnclaveFrontendRequestTransaction
|
||||
//
|
||||
|
||||
impl enclave_frontend_request_transaction::Transaction {
|
||||
pub fn from_reply(backup_id: BackupId, reply_data: &kbupd_enclave::transaction_reply::Data) -> Self {
|
||||
use enclave_frontend_request_transaction::{Transaction};
|
||||
use kbupd_enclave::transaction_reply::{Data as ReplyData};
|
||||
use kbupd_enclave::*;
|
||||
|
||||
match reply_data {
|
||||
ReplyData::CreateBackupReply(CreateBackupReply { .. }) =>
|
||||
Transaction::Create(EnclaveCreateBackupTransaction { backup_id }),
|
||||
|
||||
ReplyData::ClientResponse(kbupd_client::Response { backup: Some(backup_response), .. }) =>
|
||||
Transaction::Backup(EnclaveBackupTransaction {
|
||||
backup_id,
|
||||
status: backup_response.status.unwrap_or_default(),
|
||||
}),
|
||||
|
||||
ReplyData::ClientResponse(kbupd_client::Response { restore: Some(restore_response), .. }) =>
|
||||
Transaction::Restore(EnclaveRestoreTransaction {
|
||||
backup_id,
|
||||
status: restore_response.status.unwrap_or_default(),
|
||||
}),
|
||||
|
||||
ReplyData::ClientResponse(kbupd_client::Response { delete: Some(_), .. }) |
|
||||
ReplyData::DeleteBackupReply(DeleteBackupReply { .. }) =>
|
||||
Transaction::Delete(EnclaveDeleteBackupTransaction { backup_id }),
|
||||
|
||||
ReplyData::WrongPartition(TransactionErrorWrongPartition { new_partition, .. }) =>
|
||||
Transaction::WrongPartition(EnclaveTransactionErrorWrongPartition {
|
||||
new_partition_unknown: new_partition.is_none(),
|
||||
}),
|
||||
|
||||
ReplyData::XferInProgress(TransactionErrorXferInProgress {}) =>
|
||||
Transaction::XferInProgress(EnclaveTransactionErrorXferInProgress {}),
|
||||
|
||||
ReplyData::ClientResponse(kbupd_client::Response { backup: None, restore: None, delete: None }) |
|
||||
ReplyData::InvalidRequest(TransactionErrorInvalidRequest {}) =>
|
||||
Transaction::InvalidRequest(EnclaveTransactionErrorInvalidRequest {}),
|
||||
|
||||
ReplyData::NotLeader(TransactionErrorNotLeader { .. }) |
|
||||
ReplyData::ServiceIdMismatch(TransactionErrorServiceIdMismatch {}) |
|
||||
ReplyData::InternalError(TransactionErrorInternalError {}) =>
|
||||
Transaction::InternalError(EnclaveTransactionErrorInternalError {}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// EnclaveFrontendConfig
|
||||
//
|
||||
|
||||
impl fmt::Display for EnclaveFrontendConfig {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(self, fmt)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// EnclaveReplicaConfig
|
||||
//
|
||||
|
||||
impl fmt::Display for EnclaveReplicaConfig {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(self, fmt)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// SourcePartitionConfig
|
||||
//
|
||||
|
||||
impl fmt::Display for SourcePartitionConfig {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self { range, node_ids } = self;
|
||||
fmt.debug_struct("SourcePartitionConfig")
|
||||
.field("range", &DisplayAsDebug(range))
|
||||
.field("node_ids", &ListDisplay(node_ids.iter().map(|node_id| ToHex(node_id))))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
59
enclave/kbupd_enclave/src/protobufs_impl/kbupd_client.rs
Normal file
59
enclave/kbupd_enclave/src/protobufs_impl/kbupd_client.rs
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
use sgx_ffi::util::{clear};
|
||||
|
||||
use crate::protobufs::kbupd_client::*;
|
||||
|
||||
//
|
||||
// BackupRequest impls
|
||||
//
|
||||
|
||||
impl Drop for BackupRequest {
|
||||
fn drop(&mut self) {
|
||||
if let Some(data) = &mut self.data {
|
||||
clear(data);
|
||||
}
|
||||
if let Some(pin) = &mut self.pin {
|
||||
clear(pin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// RestoreRequest impls
|
||||
//
|
||||
|
||||
impl Drop for RestoreRequest {
|
||||
fn drop(&mut self) {
|
||||
if let Some(pin) = &mut self.pin {
|
||||
clear(pin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// RestoreResponse impls
|
||||
//
|
||||
|
||||
impl Drop for RestoreResponse {
|
||||
fn drop(&mut self) {
|
||||
if let Some(data) = &mut self.data {
|
||||
clear(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
76
enclave/kbupd_enclave/src/protobufs_impl/kbupd_enclave.rs
Normal file
76
enclave/kbupd_enclave/src/protobufs_impl/kbupd_enclave.rs
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
use std::fmt;
|
||||
|
||||
use sgx_ffi::util::{clear};
|
||||
|
||||
use crate::protobufs::kbupd::*;
|
||||
use crate::protobufs::kbupd_enclave::*;
|
||||
use crate::util::*;
|
||||
|
||||
//
|
||||
// SecretBytes impls
|
||||
//
|
||||
|
||||
impl Drop for SecretBytes {
|
||||
fn drop(&mut self) {
|
||||
clear(&mut self.data);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// FrontendRequestTransaction impls
|
||||
//
|
||||
|
||||
impl FrontendRequestTransaction {
|
||||
pub fn backup_id(&self) -> Option<&BackupId> {
|
||||
match &self.transaction {
|
||||
Some(frontend_request_transaction::Transaction::Backup(backup)) => Some(&backup.backup_id),
|
||||
Some(frontend_request_transaction::Transaction::Restore(restore)) => Some(&restore.backup_id),
|
||||
Some(frontend_request_transaction::Transaction::Create(create)) => Some(&create.backup_id),
|
||||
Some(frontend_request_transaction::Transaction::Delete(delete)) => Some(&delete.backup_id),
|
||||
None => None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// PeerConnectRequest impls
|
||||
//
|
||||
|
||||
impl fmt::Display for PeerConnectRequest {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
fmt::Debug::fmt(self, fmt)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// XferRequest impls
|
||||
//
|
||||
|
||||
impl fmt::Display for XferRequest {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
let Self { chunk_size, full_range, node_ids, group_id } = self;
|
||||
fmt.debug_struct("XferRequest")
|
||||
.field("chunk_size", chunk_size)
|
||||
.field("full_range", &DisplayAsDebug(full_range))
|
||||
.field("node_ids", &ListDisplay(node_ids.iter().map(|node_id| ToHex(node_id))))
|
||||
.field("group_id", &DisplayAsDebug(group_id))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
21
enclave/kbupd_enclave/src/protobufs_impl/mod.rs
Normal file
21
enclave/kbupd_enclave/src/protobufs_impl/mod.rs
Normal file
@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
mod kbupd;
|
||||
mod kbupd_client;
|
||||
mod kbupd_enclave;
|
||||
mod raft;
|
||||
47
enclave/kbupd_enclave/src/protobufs_impl/raft.rs
Normal file
47
enclave/kbupd_enclave/src/protobufs_impl/raft.rs
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
use std::mem;
|
||||
|
||||
use sgx_ffi::util::{clear, SecretValue};
|
||||
|
||||
use crate::protobufs::raft::*;
|
||||
|
||||
//
|
||||
// LogEntry impls
|
||||
//
|
||||
|
||||
impl LogEntry {
|
||||
pub fn new(term: TermId, data: SecretValue<Vec<u8>>) -> Self {
|
||||
Self {
|
||||
term,
|
||||
data: data.into_inner(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_data(mut self) -> SecretValue<Vec<u8>> {
|
||||
SecretValue::new(mem::replace(&mut self.data, Vec::new()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for LogEntry {
|
||||
fn drop(&mut self) {
|
||||
clear(&mut self.data);
|
||||
}
|
||||
}
|
||||
70
enclave/kbupd_enclave/src/raft.proto
Normal file
70
enclave/kbupd_enclave/src/raft.proto
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package protobufs.raft;
|
||||
|
||||
message RaftMessage {
|
||||
required RaftGroupId group = 1;
|
||||
required TermId term = 2;
|
||||
oneof inner {
|
||||
VoteRequest vote_request = 3;
|
||||
VoteResponse vote_response = 4;
|
||||
AppendRequest append_request = 5;
|
||||
AppendResponse append_response = 6;
|
||||
};
|
||||
}
|
||||
|
||||
message VoteRequest {
|
||||
required LogIdx last_log_idx = 2;
|
||||
required TermId last_log_term = 3;
|
||||
}
|
||||
|
||||
message VoteResponse {
|
||||
required bool vote_granted = 2;
|
||||
}
|
||||
|
||||
message AppendRequest {
|
||||
required LogIdx prev_log_idx = 1;
|
||||
required TermId prev_log_term = 2;
|
||||
required LogIdx leader_commit = 3;
|
||||
repeated LogEntry entries = 4;
|
||||
}
|
||||
|
||||
message AppendResponse {
|
||||
required bool success = 1;
|
||||
required LogIdx match_idx = 2;
|
||||
required LogIdx last_log_idx = 3;
|
||||
}
|
||||
|
||||
message LogEntry {
|
||||
required TermId term = 1;
|
||||
required bytes data = 2;
|
||||
}
|
||||
|
||||
message RaftGroupId {
|
||||
required bytes id = 1;
|
||||
}
|
||||
|
||||
message TermId {
|
||||
required uint64 id = 1;
|
||||
}
|
||||
|
||||
message LogIdx {
|
||||
required uint64 id = 1;
|
||||
}
|
||||
1109
enclave/kbupd_enclave/src/raft.rs
Normal file
1109
enclave/kbupd_enclave/src/raft.rs
Normal file
File diff suppressed because it is too large
Load Diff
1104
enclave/kbupd_enclave/src/remote/mod.rs
Normal file
1104
enclave/kbupd_enclave/src/remote/mod.rs
Normal file
File diff suppressed because it is too large
Load Diff
425
enclave/kbupd_enclave/src/remote/peer_manager.rs
Normal file
425
enclave/kbupd_enclave/src/remote/peer_manager.rs
Normal file
@ -0,0 +1,425 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
use std::collections::*;
|
||||
use std::rc::*;
|
||||
|
||||
use hashbrown::{HashMap, hash_map};
|
||||
use prost::{Message};
|
||||
use rand_core::{RngCore};
|
||||
use sgxsd_ffi::{RdRand};
|
||||
|
||||
use crate::{kbupd_send};
|
||||
use crate::hasher::{DefaultHasher};
|
||||
use crate::protobufs::kbupd::*;
|
||||
use crate::protobufs::kbupd_enclave::*;
|
||||
use crate::remote::*;
|
||||
|
||||
pub struct PeerManager<T> {
|
||||
node_params: Rc<NodeParams>,
|
||||
noise_buffers: SharedNoiseBuffers,
|
||||
connecting_peers: BTreeSet<ConnectingPeerState>,
|
||||
qe_info_req: QeInfoRequestState,
|
||||
peers: HashMap<NodeId, Option<T>, DefaultHasher>,
|
||||
total_ticks: u32,
|
||||
}
|
||||
|
||||
pub struct PeerStarter<'a,T,U> {
|
||||
peer_entry: hash_map::VacantEntry<'a, NodeId, Option<T>, DefaultHasher>,
|
||||
connecting_peers: &'a mut BTreeSet<ConnectingPeerState>,
|
||||
connecting_peer: ConnectingPeerState,
|
||||
remote: U,
|
||||
}
|
||||
|
||||
pub struct PeerAcceptor<'a,T> {
|
||||
peer_entry: hash_map::VacantEntry<'a, NodeId, Option<T>, DefaultHasher>,
|
||||
node_params: Rc<NodeParams>,
|
||||
noise_buffers: SharedNoiseBuffers,
|
||||
remote_node_type: NodeType,
|
||||
qe_info_req: &'a mut QeInfoRequestState,
|
||||
connect_request: PeerConnectRequest,
|
||||
}
|
||||
|
||||
pub trait Peer {
|
||||
type Message;
|
||||
fn remote_mut(&mut self) -> &mut dyn Remote;
|
||||
fn recv(&mut self, msg_data: &[u8]) -> Result<Self::Message, RemoteRecvError>;
|
||||
fn send_quote_reply(&mut self, sgx_quote: EnclaveGetQuoteReply) -> Result<(), ()>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Ord, PartialOrd)]
|
||||
struct ConnectingPeerState {
|
||||
next_timeout_tick: u32,
|
||||
last_interval_ticks: u32,
|
||||
node_id: NodeId,
|
||||
}
|
||||
|
||||
enum QeInfoRequestState {
|
||||
None,
|
||||
Sent {
|
||||
needs_qe_info: Vec<NodeId>,
|
||||
ticks_elapsed: u32,
|
||||
},
|
||||
}
|
||||
|
||||
impl<T> PeerManager<T>
|
||||
where T: Peer
|
||||
{
|
||||
pub fn new(node_type: NodeType) -> Self {
|
||||
Self {
|
||||
node_params: Rc::new(NodeParams::generate(node_type)),
|
||||
noise_buffers: Default::default(),
|
||||
connecting_peers: Default::default(),
|
||||
qe_info_req: QeInfoRequestState::None,
|
||||
peers: Default::default(),
|
||||
total_ticks: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn our_node_id(&self) -> &NodeId {
|
||||
self.node_params.node_id()
|
||||
}
|
||||
|
||||
pub fn get_peer(&self, node_id: &NodeId) -> Option<&T> {
|
||||
let peer = self.peers.get(node_id)?.as_ref()?;
|
||||
Some(peer)
|
||||
}
|
||||
|
||||
pub fn get_peer_mut(&mut self, node_id: &NodeId) -> Option<&mut T> {
|
||||
let peer = self.peers.get_mut(node_id)?.as_mut()?;
|
||||
Some(peer)
|
||||
}
|
||||
|
||||
pub fn remove_peer(&mut self, node_id: &NodeId) {
|
||||
if let hash_map::Entry::Occupied(mut peer_entry) = self.peers.entry(node_id.clone()) {
|
||||
if let Some(peer) = peer_entry.get_mut() {
|
||||
if let Some(_) = peer.remote_mut().attestation() {
|
||||
*peer_entry.get_mut() = None;
|
||||
} else {
|
||||
peer_entry.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn timer_tick(&mut self, min_timeout_ticks: u32, max_timeout_ticks: u32) {
|
||||
self.total_ticks = self.total_ticks.wrapping_add(1);
|
||||
|
||||
if let QeInfoRequestState::Sent { ticks_elapsed, .. } = &mut self.qe_info_req {
|
||||
*ticks_elapsed = ticks_elapsed.saturating_add(1);
|
||||
if *ticks_elapsed >= min_timeout_ticks {
|
||||
Self::send_get_qe_info_request();
|
||||
*ticks_elapsed = Default::default();
|
||||
}
|
||||
}
|
||||
|
||||
let mut new_connecting_peers = BTreeSet::new();
|
||||
while let Some(mut connecting_peer) = self.take_connecting_peer() {
|
||||
if let Some(peer) = self.peers.get_mut(&connecting_peer.node_id).and_then(Option::as_mut) {
|
||||
let last_interval_ticks = connecting_peer.last_interval_ticks;
|
||||
let half_interval_ticks = last_interval_ticks.min(max_timeout_ticks / 2)
|
||||
.max(min_timeout_ticks);
|
||||
let rand_interval_ticks = RdRand.next_u32().checked_rem(half_interval_ticks)
|
||||
.unwrap_or(0);
|
||||
let next_timeout_ticks = half_interval_ticks.saturating_add(rand_interval_ticks);
|
||||
|
||||
connecting_peer.last_interval_ticks = half_interval_ticks.saturating_add(half_interval_ticks);
|
||||
connecting_peer.next_timeout_tick = next_timeout_ticks.saturating_add(self.total_ticks.wrapping_add(1));
|
||||
match peer.remote_mut().connect() {
|
||||
Ok(()) => {
|
||||
info!("connecting to peer {} with retry in {} ticks, next interval {} ticks",
|
||||
peer.remote_mut().id(), next_timeout_ticks, connecting_peer.last_interval_ticks);
|
||||
Self::get_qe_info(&mut self.qe_info_req, peer.remote_mut().id().clone());
|
||||
new_connecting_peers.insert(connecting_peer);
|
||||
}
|
||||
Err(()) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
self.connecting_peers.append(&mut new_connecting_peers);
|
||||
}
|
||||
|
||||
fn take_connecting_peer(&mut self) -> Option<ConnectingPeerState> {
|
||||
if let Some(connecting_peer) = self.connecting_peers.iter().next() {
|
||||
if connecting_peer.next_timeout_tick <= self.total_ticks {
|
||||
let connecting_peer = connecting_peer.clone();
|
||||
self.connecting_peers.remove(&connecting_peer);
|
||||
Some(connecting_peer)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn start_peer<'a,M,R>(&'a mut self,
|
||||
peer_node_id: NodeId,
|
||||
peer_node_type: NodeType,
|
||||
auth_type: RemoteAuthorizationType)
|
||||
-> Result<PeerStarter<'a, T, RemoteState<M,R>>, Option<&'a mut T>>
|
||||
where M: prost::Message + 'static,
|
||||
R: prost::Message + Default + 'static,
|
||||
{
|
||||
match self.peers.entry(peer_node_id) {
|
||||
hash_map::Entry::Occupied(peer_entry) => {
|
||||
Err(peer_entry.into_mut().as_mut())
|
||||
}
|
||||
hash_map::Entry::Vacant(peer_entry) => {
|
||||
let remote = RemoteState::new(Rc::clone(&self.node_params), peer_entry.key().clone(), peer_node_type, auth_type, self.noise_buffers.clone());
|
||||
let connecting_peer = ConnectingPeerState {
|
||||
next_timeout_tick: self.total_ticks.wrapping_add(1),
|
||||
last_interval_ticks: 0,
|
||||
node_id: remote.id().clone(),
|
||||
};
|
||||
Ok(PeerStarter {
|
||||
remote,
|
||||
peer_entry,
|
||||
connecting_peers: &mut self.connecting_peers,
|
||||
connecting_peer,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request_quote(&mut self, peer_node_id: NodeId) {
|
||||
Self::get_qe_info(&mut self.qe_info_req, peer_node_id);
|
||||
}
|
||||
|
||||
fn get_qe_info(qe_info_req: &mut QeInfoRequestState, peer_node_id: NodeId) {
|
||||
if let QeInfoRequestState::None = qe_info_req {
|
||||
info!("requesting qe_info to generate quote for {}", peer_node_id);
|
||||
Self::send_get_qe_info_request();
|
||||
*qe_info_req = QeInfoRequestState::Sent {
|
||||
needs_qe_info: Default::default(),
|
||||
ticks_elapsed: Default::default(),
|
||||
};
|
||||
}
|
||||
if let QeInfoRequestState::Sent { needs_qe_info, .. } = qe_info_req {
|
||||
needs_qe_info.push(peer_node_id);
|
||||
} else {
|
||||
static_unreachable!();
|
||||
}
|
||||
}
|
||||
|
||||
fn send_get_qe_info_request() {
|
||||
kbupd_send(EnclaveMessage {
|
||||
inner: Some(enclave_message::Inner::GetQeInfoRequest(GetQeInfoRequest {})),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn get_qe_info_reply(&mut self, get_qe_info_reply: GetQeInfoReply) {
|
||||
if let QeInfoRequestState::Sent { needs_qe_info, .. } =
|
||||
std::mem::replace(&mut self.qe_info_req, QeInfoRequestState::None)
|
||||
{
|
||||
info!("generating quotes for {} peers", needs_qe_info.len());
|
||||
for peer_node_id in needs_qe_info {
|
||||
if let Some(peer) = self.peers.get_mut(&peer_node_id).and_then(Option::as_mut) {
|
||||
match peer.remote_mut().qe_info_reply(&get_qe_info_reply) {
|
||||
Ok(get_quote_request) => {
|
||||
kbupd_send(EnclaveMessage {
|
||||
inner: Some(enclave_message::Inner::GetQuoteRequest(get_quote_request)),
|
||||
});
|
||||
}
|
||||
Err(()) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_quote_reply(&mut self, get_quote_reply: GetQuoteReply) {
|
||||
let peer_node_id = NodeId::from(&get_quote_reply.request_id);
|
||||
if let Some(peer) = self.peers.get_mut(&peer_node_id).and_then(Option::as_mut) {
|
||||
match peer.remote_mut().get_quote_reply(get_quote_reply) {
|
||||
Ok(Some(get_attestation_request)) => {
|
||||
kbupd_send(EnclaveMessage {
|
||||
inner: Some(enclave_message::Inner::GetAttestationRequest(get_attestation_request)),
|
||||
});
|
||||
}
|
||||
Err(Some(enclave_get_quote_reply)) => {
|
||||
let _ignore = peer.send_quote_reply(enclave_get_quote_reply);
|
||||
}
|
||||
Ok(None) => (),
|
||||
Err(None) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn request_attestation(&mut self, sgx_quote: Vec<u8>, peer_node_id: NodeId) {
|
||||
info!("fetching attestation for peer {}", &peer_node_id);
|
||||
kbupd_send(EnclaveMessage {
|
||||
inner: Some(enclave_message::Inner::GetAttestationRequest(GetAttestationRequest {
|
||||
request_id: peer_node_id.to_vec(),
|
||||
sgx_quote,
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn get_attestation_reply(&mut self, get_attestation_reply: GetAttestationReply) -> Option<(&mut T, AttestationParameters)> {
|
||||
let peer_node_id: NodeId = get_attestation_reply.request_id.into();
|
||||
let peer = self.peers.get_mut(&peer_node_id)?.as_mut()?;
|
||||
match peer.remote_mut().attestation_reply(get_attestation_reply.ias_report) {
|
||||
Ok(Some(attestation)) => Some((peer, attestation)),
|
||||
Ok(None) => None,
|
||||
Err(()) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_message_signal(&mut self, message: NewMessageSignal) -> Result<Option<(&mut T, <T as Peer>::Message)>, PeerAcceptor<'_,T>> {
|
||||
let peer_node_id: NodeId = message.node_id.into();
|
||||
|
||||
if message.syn {
|
||||
let connect_request = match PeerConnectRequest::decode(&message.data[..]) {
|
||||
Ok(connect_request) => connect_request,
|
||||
Err(decode_error) => {
|
||||
warn!("dropping connect request from {}: {}", &peer_node_id, decode_error);
|
||||
return Ok(None);
|
||||
}
|
||||
};
|
||||
match self.peer_connect_request(connect_request, peer_node_id) {
|
||||
Some(peer_acceptor) => Err(peer_acceptor),
|
||||
None => Ok(None),
|
||||
}
|
||||
} else {
|
||||
match self.peer_message(message.data, peer_node_id) {
|
||||
Ok(result) => Ok(result),
|
||||
Err(()) => Ok(None),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn peer_message(&mut self, message_data: Vec<u8>, peer_node_id: NodeId) -> Result<Option<(&mut T, <T as Peer>::Message)>, ()> {
|
||||
let peer_entry = self.peers.get_mut(&peer_node_id);
|
||||
if let Some(Some(peer)) = peer_entry {
|
||||
match peer.recv(&message_data) {
|
||||
Ok(message) => {
|
||||
Ok(Some((peer, message)))
|
||||
}
|
||||
Err(RemoteRecvError::NeedsAttestation(get_attestation_request)) => {
|
||||
info!("fetching attestation for peer {}", &peer_node_id);
|
||||
kbupd_send(EnclaveMessage {
|
||||
inner: Some(enclave_message::Inner::GetAttestationRequest(get_attestation_request)),
|
||||
});
|
||||
Ok(None)
|
||||
}
|
||||
Err(RemoteRecvError::DecodeError) |
|
||||
Err(RemoteRecvError::InvalidState) => {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
} else if let Some(None) = peer_entry {
|
||||
warn!("dropping message from evicted peer {}", &peer_node_id);
|
||||
Err(())
|
||||
} else {
|
||||
error!("dropping message from missing peer {}", &peer_node_id);
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
fn peer_connect_request(&mut self, connect_request: PeerConnectRequest, peer_node_id: NodeId) -> Option<PeerAcceptor<'_,T>> {
|
||||
match self.peers.entry(peer_node_id) {
|
||||
hash_map::Entry::Occupied(mut peer_entry) => {
|
||||
if let Some(peer) = peer_entry.get_mut().as_mut() {
|
||||
match peer.remote_mut().accept(connect_request) {
|
||||
Ok(()) => {
|
||||
Self::get_qe_info(&mut self.qe_info_req, peer_entry.key().clone());
|
||||
}
|
||||
Err(()) => (),
|
||||
}
|
||||
} else {
|
||||
warn!("dropping connect request from evicted peer {}", peer_entry.key());
|
||||
}
|
||||
None
|
||||
}
|
||||
hash_map::Entry::Vacant(peer_entry) => {
|
||||
if let Some(remote_node_type) = NodeType::from_i32(connect_request.node_type) {
|
||||
Some(PeerAcceptor {
|
||||
peer_entry,
|
||||
node_params: Rc::clone(&self.node_params),
|
||||
noise_buffers: self.noise_buffers.clone(),
|
||||
remote_node_type,
|
||||
qe_info_req: &mut self.qe_info_req,
|
||||
connect_request,
|
||||
})
|
||||
} else {
|
||||
warn!("dropping connect request from {}: invalid node type {}",
|
||||
peer_entry.key(), connect_request.node_type);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// PeerStarter impls
|
||||
//
|
||||
|
||||
impl<'a,T,U> PeerStarter<'a,T,U>
|
||||
where T: Peer,
|
||||
U: Remote
|
||||
{
|
||||
pub fn remote(&self) -> &U {
|
||||
&self.remote
|
||||
}
|
||||
pub fn connect<F>(mut self, mapper: F) -> Result<&'a mut T, (Self, F)>
|
||||
where F: FnOnce(U) -> T,
|
||||
{
|
||||
match self.remote.connect() {
|
||||
Ok(()) => {
|
||||
self.connecting_peers.insert(self.connecting_peer);
|
||||
let peer = self.peer_entry.insert(Some(mapper(self.remote)));
|
||||
Ok(peer.as_mut().unwrap_or_else(|| unreachable!()))
|
||||
}
|
||||
Err(()) => {
|
||||
Err((self, mapper))
|
||||
}
|
||||
}
|
||||
}
|
||||
pub fn insert(self, mapper: impl FnOnce(U) -> T) -> &'a mut T {
|
||||
self.peer_entry.insert(Some(mapper(self.remote)))
|
||||
.as_mut()
|
||||
.unwrap_or_else(|| unreachable!())
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// PeerAcceptor impls
|
||||
//
|
||||
|
||||
impl<'a,T> PeerAcceptor<'a,T>
|
||||
where T: Peer
|
||||
{
|
||||
pub fn node_id(&self) -> &NodeId {
|
||||
self.peer_entry.key()
|
||||
}
|
||||
pub fn connect_request(&self) -> &PeerConnectRequest {
|
||||
&self.connect_request
|
||||
}
|
||||
pub fn accept<M,R>(self, mapper: impl FnOnce(RemoteState<M,R>) -> T, auth_type: RemoteAuthorizationType) -> Result<&'a mut T, ()>
|
||||
where M: prost::Message + 'static,
|
||||
R: prost::Message + Default + 'static,
|
||||
{
|
||||
let mut remote = RemoteState::new(Rc::clone(&self.node_params), self.peer_entry.key().clone(), self.remote_node_type, auth_type, self.noise_buffers);
|
||||
remote.accept(self.connect_request)?;
|
||||
PeerManager::<T>::get_qe_info(self.qe_info_req, self.peer_entry.key().clone());
|
||||
let peer = self.peer_entry.insert(Some(mapper(remote)));
|
||||
Ok(peer.as_mut().unwrap_or_else(|| unreachable!()))
|
||||
}
|
||||
}
|
||||
156
enclave/kbupd_enclave/src/remote/sgx_quote.rs
Normal file
156
enclave/kbupd_enclave/src/remote/sgx_quote.rs
Normal file
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
use bytes::{Buf};
|
||||
use num_traits::{ToPrimitive};
|
||||
|
||||
const SGX_FLAGS_INITTED: u64 = 0x0000_0000_0000_0001;
|
||||
const SGX_FLAGS_DEBUG: u64 = 0x0000_0000_0000_0002;
|
||||
const SGX_FLAGS_MODE64BIT: u64 = 0x0000_0000_0000_0004;
|
||||
const SGX_FLAGS_RESERVED: u64 = 0xFFFF_FFFF_FFFF_FFC8;
|
||||
const SGX_XFRM_RESERVED: u64 = 0xFFFF_FFFF_FFFF_FFF8;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SgxQuote {
|
||||
pub version: u16,
|
||||
pub is_sig_linkable: bool,
|
||||
pub gid: u32,
|
||||
pub qe_svn: u16,
|
||||
pub pce_svn: u16,
|
||||
pub basename: [u8; 32],
|
||||
pub cpu_svn: [u8; 16],
|
||||
pub flags: u64,
|
||||
pub xfrm: u64,
|
||||
pub mrenclave: [u8; 32],
|
||||
pub mrsigner: [u8; 32],
|
||||
pub isv_prod_id: u16,
|
||||
pub isv_svn: u16,
|
||||
pub report_data: SgxReportData,
|
||||
pub has_signature: bool,
|
||||
}
|
||||
|
||||
pub struct SgxReportData(pub [u8; 64]);
|
||||
|
||||
impl Default for SgxReportData {
|
||||
fn default() -> Self {
|
||||
Self([0; 64])
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum SgxQuoteDecodeError {
|
||||
Truncated(usize),
|
||||
NonZeroReserved(usize),
|
||||
UnknownVersion(u16),
|
||||
UnknownSignType(u16),
|
||||
InvalidFlags(u64),
|
||||
InvalidXfrm(u64),
|
||||
InvalidSignatureLength(u32),
|
||||
}
|
||||
|
||||
impl SgxQuote {
|
||||
pub fn decode(quote_buf: &mut impl Buf) -> Result<Self, SgxQuoteDecodeError> {
|
||||
if quote_buf.remaining() < 432 {
|
||||
return Err(SgxQuoteDecodeError::Truncated(quote_buf.remaining()));
|
||||
}
|
||||
|
||||
let mut quote: Self = Default::default();
|
||||
|
||||
quote.version = quote_buf.get_u16_le();
|
||||
if !(quote.version >= 1 && quote.version <= 2) {
|
||||
return Err(SgxQuoteDecodeError::UnknownVersion(quote.version));
|
||||
}
|
||||
|
||||
let sign_type = quote_buf.get_u16_le();
|
||||
if (sign_type & !1) != 0 {
|
||||
return Err(SgxQuoteDecodeError::UnknownSignType(sign_type));
|
||||
}
|
||||
|
||||
quote.is_sig_linkable = sign_type == 1;
|
||||
quote.gid = quote_buf.get_u32_le();
|
||||
quote.qe_svn = quote_buf.get_u16_le();
|
||||
|
||||
if quote.version > 1 {
|
||||
quote.pce_svn = quote_buf.get_u16_le();
|
||||
} else {
|
||||
Self::read_zero(quote_buf, 10, 2)?;
|
||||
quote.pce_svn = 0;
|
||||
}
|
||||
|
||||
Self::read_zero(quote_buf, 12, 4)?; // xeid (reserved)
|
||||
quote_buf.copy_to_slice(&mut quote.basename);
|
||||
|
||||
//
|
||||
// report_body
|
||||
//
|
||||
|
||||
quote_buf.copy_to_slice(&mut quote.cpu_svn);
|
||||
Self::read_zero(quote_buf, 64, 4)?; // misc_select (reserved)
|
||||
Self::read_zero(quote_buf, 68, 28)?; // reserved1
|
||||
|
||||
quote.flags = quote_buf.get_u64_le();
|
||||
if ((quote.flags & SGX_FLAGS_RESERVED ) != 0 ||
|
||||
(quote.flags & SGX_FLAGS_INITTED ) == 0 ||
|
||||
(quote.flags & SGX_FLAGS_MODE64BIT) == 0)
|
||||
{
|
||||
return Err(SgxQuoteDecodeError::InvalidFlags(quote.flags));
|
||||
}
|
||||
|
||||
quote.xfrm = quote_buf.get_u64_le();
|
||||
if (quote.xfrm & SGX_XFRM_RESERVED) != 0 {
|
||||
return Err(SgxQuoteDecodeError::InvalidXfrm(quote.xfrm));
|
||||
}
|
||||
|
||||
quote_buf.copy_to_slice(&mut quote.mrenclave);
|
||||
Self::read_zero(quote_buf, 144, 32)?; // reserved2
|
||||
quote_buf.copy_to_slice(&mut quote.mrsigner);
|
||||
Self::read_zero(quote_buf, 208, 96)?; // reserved3
|
||||
quote.isv_prod_id = quote_buf.get_u16_le();
|
||||
quote.isv_svn = quote_buf.get_u16_le();
|
||||
Self::read_zero(quote_buf, 308, 60)?; // reserved4
|
||||
quote_buf.copy_to_slice(&mut quote.report_data.0);
|
||||
|
||||
//
|
||||
// quote signature
|
||||
//
|
||||
|
||||
if quote_buf.remaining() != 0 {
|
||||
let signature_length = quote_buf.get_u32_le();
|
||||
if quote_buf.remaining().to_u32() != Some(signature_length) {
|
||||
return Err(SgxQuoteDecodeError::InvalidSignatureLength(signature_length));
|
||||
}
|
||||
quote.has_signature = true;
|
||||
} else {
|
||||
quote.has_signature = false;
|
||||
}
|
||||
|
||||
Ok(quote)
|
||||
}
|
||||
|
||||
pub fn is_debug_quote(&self) -> bool {
|
||||
(self.flags & SGX_FLAGS_DEBUG) != 0
|
||||
}
|
||||
|
||||
fn read_zero(buf: &mut impl Buf, pos: usize, count: usize) -> Result<(), SgxQuoteDecodeError> {
|
||||
for _ in 0..count {
|
||||
if buf.get_u8() != 0 {
|
||||
return Err(SgxQuoteDecodeError::NonZeroReserved(pos));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
426
enclave/kbupd_enclave/src/remote_group.rs
Normal file
426
enclave/kbupd_enclave/src/remote_group.rs
Normal file
@ -0,0 +1,426 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
use std::collections::*;
|
||||
use std::fmt;
|
||||
use std::rc::*;
|
||||
|
||||
use rand_core::{RngCore};
|
||||
use sgxsd_ffi::{RdRand};
|
||||
|
||||
use crate::protobufs::kbupd::*;
|
||||
use crate::protobufs::kbupd_enclave::*;
|
||||
use crate::protobufs::raft::*;
|
||||
use crate::remote::*;
|
||||
use crate::util::*;
|
||||
|
||||
pub trait RemoteGroupPendingRequest {
|
||||
type RequestId: Clone + Ord + Eq;
|
||||
type Message: prost::Message;
|
||||
fn request_id(&self) -> &Self::RequestId;
|
||||
fn message(&self) -> Rc<Self::Message>;
|
||||
fn min_attestation(&self) -> Option<AttestationParameters>;
|
||||
}
|
||||
|
||||
pub trait RemoteGroupNode {
|
||||
fn request_quote(&mut self, request: EnclaveGetQuoteRequest) -> Result<(), ()>;
|
||||
}
|
||||
|
||||
pub struct RemoteGroupState<T,R>
|
||||
where R: RemoteGroupPendingRequest,
|
||||
{
|
||||
name: String,
|
||||
nodes: Box<[RemoteGroupNodeState<T, R::RequestId>]>,
|
||||
leader: Option<usize>,
|
||||
term: TermId,
|
||||
pending: BTreeMap<R::RequestId, PendingRequestState<R>>,
|
||||
|
||||
timeout_ticks: u32,
|
||||
request_quote_ticks: u32,
|
||||
total_ticks: u32,
|
||||
}
|
||||
|
||||
pub enum RemoteGroupSendError<R> {
|
||||
NotYetValid(R),
|
||||
AlreadySent(R),
|
||||
}
|
||||
|
||||
struct PendingRequestState<R> {
|
||||
request: R,
|
||||
sent_at_tick: u32,
|
||||
}
|
||||
|
||||
//
|
||||
// RemoteGroupState impls
|
||||
//
|
||||
|
||||
struct RemoteGroupNodeState<T, RequestId> {
|
||||
remote: T,
|
||||
last_sent: Option<RequestId>,
|
||||
}
|
||||
|
||||
impl<T,R> RemoteGroupState<T,R>
|
||||
where T: RemoteMessageSender<Message = R::Message> + 'static,
|
||||
T: RemoteGroupNode,
|
||||
R: RemoteGroupPendingRequest + 'static,
|
||||
{
|
||||
pub fn new(name: String, remotes: Vec<T>) -> Self {
|
||||
let nodes = remotes.into_iter().map(|remote: T| RemoteGroupNodeState {
|
||||
remote,
|
||||
last_sent: Default::default(),
|
||||
});
|
||||
Self {
|
||||
name,
|
||||
nodes: nodes.collect::<Vec<_>>().into(),
|
||||
leader: Default::default(),
|
||||
term: Default::default(),
|
||||
pending: Default::default(),
|
||||
|
||||
timeout_ticks: Default::default(),
|
||||
request_quote_ticks: Default::default(),
|
||||
total_ticks: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn pending_len(&self) -> usize {
|
||||
self.pending.len()
|
||||
}
|
||||
|
||||
pub fn trim_to(&mut self, trim_to_len: usize, ttl_ticks: u32) -> impl DoubleEndedIterator<Item = R> + ExactSizeIterator {
|
||||
let mut maybe_trim_key: Option<&R::RequestId> = None;
|
||||
if let Some(trim_count) = self.pending.len().checked_sub(trim_to_len) {
|
||||
for (pending_request_id, pending_request) in self.pending.iter().take(trim_count) {
|
||||
if self.total_ticks.checked_sub(pending_request.sent_at_tick) < Some(ttl_ticks) {
|
||||
break;
|
||||
}
|
||||
maybe_trim_key = Some(pending_request_id);
|
||||
}
|
||||
}
|
||||
let trimmed = if let Some(trim_key) = maybe_trim_key {
|
||||
let split_off = if let Some((new_first_key, _)) = self.pending.range(trim_key..).nth(1) {
|
||||
let new_first_key = new_first_key.clone();
|
||||
self.pending.split_off(&new_first_key)
|
||||
} else {
|
||||
BTreeMap::new()
|
||||
};
|
||||
std::mem::replace(&mut self.pending, split_off)
|
||||
} else {
|
||||
BTreeMap::new()
|
||||
};
|
||||
|
||||
trimmed.into_iter()
|
||||
.map(|(_, pending_request_state): (_, PendingRequestState<R>)| {
|
||||
pending_request_state.request
|
||||
})
|
||||
}
|
||||
|
||||
pub fn reset_peer(&mut self, node_id: &NodeId) {
|
||||
match self.get_node_mut(node_id) {
|
||||
Some(from_node) => {
|
||||
from_node.last_sent = Default::default();
|
||||
}
|
||||
None => return,
|
||||
}
|
||||
warn!("resetting group {} peer {}", &self.name, node_id);
|
||||
let maybe_old_leader =
|
||||
self.leader.and_then(|leader: usize| self.nodes.get(leader))
|
||||
.map(|leader: &RemoteGroupNodeState<T, _>| leader.remote.id());
|
||||
|
||||
if maybe_old_leader == Some(node_id) {
|
||||
self.leader = None;
|
||||
self.choose_leader();
|
||||
}
|
||||
self.flush_requests();
|
||||
}
|
||||
|
||||
pub fn contains_authorized_node(&self, node_id: &NodeId) -> bool {
|
||||
if let Some(node) = self.get_node(node_id) {
|
||||
node.remote.attestation().is_some()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn status(&self) -> Vec<EnclavePeerStatus> {
|
||||
let mut statuses = Vec::with_capacity(self.nodes.len());
|
||||
for (node_idx, node) in self.nodes.iter().enumerate() {
|
||||
let unsent_requests = if let Some(last_sent) = &node.last_sent {
|
||||
self.pending.range(last_sent..).count().saturating_sub(1)
|
||||
} else {
|
||||
self.pending.len()
|
||||
};
|
||||
let inflight_requests = self.pending.len().saturating_sub(unsent_requests);
|
||||
statuses.push(EnclavePeerStatus {
|
||||
node_id: node.remote.id().to_vec(),
|
||||
attestation: node.remote.attestation(),
|
||||
replication_status: None,
|
||||
is_leader: Some(node_idx) == self.leader,
|
||||
unsent_requests: unsent_requests.to_u64(),
|
||||
inflight_requests: inflight_requests.to_u64(),
|
||||
})
|
||||
}
|
||||
statuses
|
||||
}
|
||||
|
||||
fn get_node_mut(&mut self, node_id: &NodeId) -> Option<&mut RemoteGroupNodeState<T, R::RequestId>> {
|
||||
self.nodes.iter_mut().find_map(|node: &mut RemoteGroupNodeState<T, _>| {
|
||||
if node.remote.id() == node_id {
|
||||
Some(node)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn get_node(&self, node_id: &NodeId) -> Option<&RemoteGroupNodeState<T, R::RequestId>> {
|
||||
self.nodes.iter().find_map(|node: &RemoteGroupNodeState<T, _>| {
|
||||
if node.remote.id() == node_id {
|
||||
Some(node)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn get_leader_node(&self) -> Option<&RemoteGroupNodeState<T, R::RequestId>> {
|
||||
if let Some(leader) = &self.leader {
|
||||
self.nodes.get(*leader)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn timer_tick(&mut self, max_timeout_ticks: u32, max_request_quote_ticks: u32) {
|
||||
self.timeout_ticks = self.timeout_ticks.saturating_add(1);
|
||||
self.request_quote_ticks = self.request_quote_ticks.saturating_add(1);
|
||||
self.total_ticks = self.total_ticks.wrapping_add(1);
|
||||
if self.timeout_ticks >= max_timeout_ticks {
|
||||
self.timeout_ticks = Default::default();
|
||||
|
||||
if !self.pending.is_empty() {
|
||||
if let Some(leader) = self.get_leader_node() {
|
||||
info!("group {} timeout on leader {}", &self.name, leader.remote.id());
|
||||
self.leader = None;
|
||||
}
|
||||
self.choose_leader();
|
||||
}
|
||||
}
|
||||
if self.request_quote_ticks >= max_request_quote_ticks {
|
||||
self.request_quote_ticks = Default::default();
|
||||
|
||||
for node in &mut self.nodes[..] {
|
||||
let _ignore = node.remote.request_quote(EnclaveGetQuoteRequest {});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remote_authorized(&mut self, node_id: &NodeId) {
|
||||
if self.get_node(node_id).is_some() {
|
||||
self.choose_leader();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remote_not_leader(&mut self, term: TermId, maybe_new_leader: Option<&NodeId>, from_node_id: &NodeId) {
|
||||
match self.get_node_mut(from_node_id) {
|
||||
Some(from_node) => {
|
||||
from_node.last_sent = Default::default();
|
||||
}
|
||||
None => return,
|
||||
}
|
||||
let nodes = &self.nodes[..];
|
||||
|
||||
let maybe_old_leader =
|
||||
self.leader.and_then(|leader: usize| nodes.get(leader))
|
||||
.map(|leader: &RemoteGroupNodeState<T, _>| leader.remote.id());
|
||||
if term >= self.term {
|
||||
self.term = term;
|
||||
// prevent re-send storm from a node responding NotLeader while contradictorily asserting itself as leader
|
||||
if let Some(new_leader) = maybe_new_leader.filter(|new_leader: &&NodeId| new_leader != &from_node_id) {
|
||||
if Some(new_leader) != maybe_old_leader {
|
||||
info!("group {} changed leader to {} at term {}", &self.name, new_leader, &self.term.id);
|
||||
self.leader = nodes.iter().position(|node: &RemoteGroupNodeState<T, _>| node.remote.id() == new_leader);
|
||||
}
|
||||
} else if let Some(old_leader) = maybe_old_leader {
|
||||
info!("group {} lost leader {} at term {}", &self.name, old_leader, &self.term.id);
|
||||
self.leader = None;
|
||||
}
|
||||
} else if let Some(old_leader) = maybe_old_leader {
|
||||
if old_leader == from_node_id {
|
||||
info!("group {} lost leader {} at term {}", &self.name, old_leader, &self.term.id);
|
||||
self.leader = None;
|
||||
}
|
||||
}
|
||||
self.flush_requests();
|
||||
}
|
||||
|
||||
pub fn send(&mut self, request: R) -> Result<(), RemoteGroupSendError<R>> {
|
||||
let request_id = request.request_id().clone();
|
||||
let message = request.message();
|
||||
|
||||
if Some(&request_id) < self.pending.keys().last() {
|
||||
return Err(RemoteGroupSendError::AlreadySent(request));
|
||||
}
|
||||
|
||||
let nodes = &mut self.nodes[..];
|
||||
let maybe_authorized_leader =
|
||||
self.leader.and_then(|leader: usize| nodes.get_mut(leader))
|
||||
.filter(|leader: &&mut RemoteGroupNodeState<T, _>| leader.remote.attestation().is_some());
|
||||
if let btree_map::Entry::Vacant(pending_request_entry) = self.pending.entry(request_id) {
|
||||
let sent_at_tick = self.total_ticks;
|
||||
if let Some(authorized_leader) = maybe_authorized_leader {
|
||||
if request.min_attestation() <= authorized_leader.remote.attestation() {
|
||||
authorized_leader.send(message);
|
||||
authorized_leader.mark_sent(Some(request.request_id()));
|
||||
pending_request_entry.insert(PendingRequestState { request, sent_at_tick });
|
||||
Ok(())
|
||||
} else {
|
||||
Err(RemoteGroupSendError::NotYetValid(request))
|
||||
}
|
||||
} else {
|
||||
pending_request_entry.insert(PendingRequestState { request, sent_at_tick });
|
||||
Ok(())
|
||||
}
|
||||
} else {
|
||||
Err(RemoteGroupSendError::AlreadySent(request))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle_reply(&mut self, request_id: &R::RequestId) -> Option<R> {
|
||||
self.timeout_ticks = Default::default();
|
||||
self.pending.remove(request_id)
|
||||
.map(|request_state: PendingRequestState<R>| request_state.request)
|
||||
}
|
||||
|
||||
pub fn get_remotes(&self) -> Vec<NodeId> {
|
||||
self.nodes[..].iter().map(|node: &RemoteGroupNodeState<T, _>| node.remote.id().clone()).collect()
|
||||
}
|
||||
|
||||
#[allow(clippy::indexing_slicing, clippy::integer_arithmetic)]
|
||||
fn choose_leader(&mut self) {
|
||||
if self.get_leader_node().is_none() {
|
||||
let mut nodes: Vec<usize> = (0..self.nodes.len()).collect();
|
||||
for nodes_idx in 0..nodes.len() {
|
||||
let rand = (RdRand.next_u32().to_usize()) % (self.nodes.len() - nodes_idx);
|
||||
nodes.swap(nodes_idx, nodes_idx.wrapping_add(rand));
|
||||
|
||||
let node_idx = nodes[nodes_idx];
|
||||
let node = &self.nodes[node_idx];
|
||||
if (node.remote.attestation().is_some() &&
|
||||
self.has_unsent_to(node))
|
||||
{
|
||||
self.leader = Some(node_idx);
|
||||
self.timeout_ticks = Default::default();
|
||||
info!("group {} chose random leader {}", &self.name, node.remote.id());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
self.flush_requests();
|
||||
}
|
||||
|
||||
fn flush_requests(&mut self) {
|
||||
let nodes = &mut self.nodes[..];
|
||||
let maybe_authorized_leader =
|
||||
self.leader.and_then(|leader: usize| nodes.get_mut(leader))
|
||||
.filter(|leader: &&mut RemoteGroupNodeState<T, _>| leader.remote.attestation().is_some());
|
||||
if let Some(authorized_leader) = maybe_authorized_leader {
|
||||
let mut queue = Vec::new();
|
||||
let mut not_yet_valid_count: u64 = 0;
|
||||
let mut last_sent_request_id: Option<&R::RequestId> = None;
|
||||
for pending_request in self.pending.values_mut() {
|
||||
if !authorized_leader.has_sent(&pending_request.request) {
|
||||
if pending_request.request.min_attestation() <= authorized_leader.remote.attestation() {
|
||||
last_sent_request_id = Some(pending_request.request.request_id());
|
||||
queue.push(pending_request.request.message());
|
||||
} else {
|
||||
not_yet_valid_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if not_yet_valid_count > 0 {
|
||||
info!("group {} not sending {} messages to new leader {} due to attestation timestamp {}",
|
||||
&self.name, not_yet_valid_count, authorized_leader.remote.id(),
|
||||
OptionDisplay(authorized_leader.remote.attestation().as_ref()));
|
||||
}
|
||||
if !queue.is_empty() {
|
||||
info!("group {} resending {} messages to new leader {}",
|
||||
&self.name, queue.len(), authorized_leader.remote.id());
|
||||
for message in queue {
|
||||
authorized_leader.send(message);
|
||||
}
|
||||
}
|
||||
authorized_leader.mark_sent(last_sent_request_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn has_unsent_to(&self, node: &RemoteGroupNodeState<T, R::RequestId>) -> bool {
|
||||
if let Some(last_request) = self.pending.values().last() {
|
||||
!node.has_sent(&last_request.request)
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, RequestId> RemoteGroupNodeState<T, RequestId>
|
||||
where T: RemoteMessageSender + 'static,
|
||||
RequestId: Clone + Ord + Eq,
|
||||
{
|
||||
fn send(&self, request: Rc<T::Message>) {
|
||||
let _ignore = self.remote.send(request);
|
||||
}
|
||||
fn mark_sent(&mut self, sent_request_id: Option<&RequestId>) {
|
||||
if sent_request_id > self.last_sent.as_ref() {
|
||||
self.last_sent = sent_request_id.cloned();
|
||||
}
|
||||
}
|
||||
fn has_sent<R>(&self, request: &R) -> bool
|
||||
where R: RemoteGroupPendingRequest<RequestId = RequestId> + 'static,
|
||||
{
|
||||
Some(request.request_id()) <= self.last_sent.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T,R> fmt::Display for RemoteGroupState<T,R>
|
||||
where T: RemoteMessageSender<Message = R::Message> + RemoteGroupNode + 'static,
|
||||
R: RemoteGroupPendingRequest + 'static,
|
||||
{
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt.debug_struct("RemoteGroupState")
|
||||
.field("name", &self.name)
|
||||
.field("nodes", &ListDisplay(self.nodes.iter().map(|node| node.remote.id())))
|
||||
.field("leader", &OptionDisplay(self.get_leader_node().map(|node| node.remote.id())))
|
||||
.field("term", &DisplayAsDebug(self.term))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R> fmt::Display for RemoteGroupSendError<R> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let name = match self {
|
||||
RemoteGroupSendError::AlreadySent(_) => "AlreadySent",
|
||||
RemoteGroupSendError::NotYetValid(_) => "NotYetValid",
|
||||
};
|
||||
write!(fmt, "{}", name)
|
||||
}
|
||||
}
|
||||
955
enclave/kbupd_enclave/src/service/frontend.rs
Normal file
955
enclave/kbupd_enclave/src/service/frontend.rs
Normal file
@ -0,0 +1,955 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
use std::cmp::{Ordering};
|
||||
use std::ops::{Add};
|
||||
use std::rc::*;
|
||||
use std::time::*;
|
||||
|
||||
use hashbrown::{HashMap};
|
||||
use prost::{Message};
|
||||
use sgx_ffi::util::{SecretValue};
|
||||
use sgxsd_ffi::ecalls::{SgxsdMsgFrom};
|
||||
|
||||
use crate::{kbupd_send};
|
||||
use crate::ffi::ecalls::*;
|
||||
use crate::hasher::{DefaultHasher};
|
||||
use crate::protobufs::kbupd::*;
|
||||
use crate::protobufs::kbupd_client;
|
||||
use crate::protobufs::kbupd_enclave::*;
|
||||
use crate::protobufs::raft::*;
|
||||
use crate::util::*;
|
||||
use crate::remote::*;
|
||||
use crate::remote_group::*;
|
||||
use crate::service::replica::{PartitionKeyRange};
|
||||
|
||||
const NODE_TYPE: NodeType = NodeType::Frontend;
|
||||
|
||||
//
|
||||
// data structures
|
||||
//
|
||||
|
||||
pub struct FrontendState {
|
||||
config: EnclaveFrontendConfig,
|
||||
replicas: PeerManager<Replica>,
|
||||
partitions: HashMap<RaftGroupId, Partition, DefaultHasher>,
|
||||
key_ranges: PartitionKeyRanges,
|
||||
last_request_id: PendingRequestId,
|
||||
}
|
||||
|
||||
type RemoteReplicaMessageSender = RemoteSender<FrontendToReplicaMessage>;
|
||||
|
||||
struct Replica {
|
||||
remote: RemoteState<FrontendToReplicaMessage, ReplicaToFrontendMessage>,
|
||||
group_id: RaftGroupId,
|
||||
}
|
||||
|
||||
struct Partition {
|
||||
remote_group: RemoteGroupState<RemoteReplicaMessageSender, PendingRequest>,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct PartitionKeyRanges {
|
||||
ranges: Vec<(PartitionKeyRange, RaftGroupId)>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
|
||||
struct PendingRequestId {
|
||||
id: u64,
|
||||
}
|
||||
|
||||
#[allow(variant_size_differences)]
|
||||
enum PendingRequestFrom {
|
||||
Client(PendingClientRequest),
|
||||
Untrusted {
|
||||
untrusted_request_id: u64,
|
||||
}
|
||||
}
|
||||
|
||||
struct PendingRequest {
|
||||
id: PendingRequestId,
|
||||
message: Rc<FrontendToReplicaMessage>,
|
||||
min_attestation: Option<AttestationParameters>,
|
||||
from: PendingRequestFrom,
|
||||
}
|
||||
|
||||
pub struct PendingClientRequest {
|
||||
from: SgxsdMsgFrom,
|
||||
}
|
||||
|
||||
//
|
||||
// FrontendState impls
|
||||
//
|
||||
|
||||
impl FrontendState {
|
||||
pub fn init(request: StartFrontendRequest) -> Self {
|
||||
let mut state = Self {
|
||||
config: request.config,
|
||||
replicas: PeerManager::new(NODE_TYPE),
|
||||
partitions: Default::default(),
|
||||
key_ranges: Default::default(),
|
||||
last_request_id: Default::default(),
|
||||
};
|
||||
|
||||
for partition_config in request.partitions {
|
||||
state.update_partition(partition_config);
|
||||
}
|
||||
|
||||
kbupd_send(EnclaveMessage {
|
||||
inner: Some(enclave_message::Inner::StartFrontendReply(StartFrontendReply {
|
||||
node_id: state.replicas.our_node_id().to_vec(),
|
||||
})),
|
||||
});
|
||||
|
||||
state
|
||||
}
|
||||
|
||||
fn update_partition(&mut self, config: PartitionConfig) {
|
||||
let PartitionConfig { group_id, range, node_ids } = config;
|
||||
let group_id = RaftGroupId { id: group_id };
|
||||
if let Some(range) = range {
|
||||
match PartitionKeyRange::try_from_pb(&range) {
|
||||
Ok(range) => {
|
||||
self.key_ranges.update(&group_id, range);
|
||||
}
|
||||
Err(()) => {
|
||||
error!("received partition config for {} with invalid range: {}", &group_id, &range);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.key_ranges.remove(&group_id);
|
||||
}
|
||||
if !self.partitions.contains_key(&group_id) {
|
||||
let mut remotes = Vec::with_capacity(node_ids.len());
|
||||
for replica_node_id in node_ids {
|
||||
if let Some(replica) = self.start_replica_remote(replica_node_id[..].into(), group_id.clone()) {
|
||||
remotes.push(replica.remote.sender().clone());
|
||||
} else {
|
||||
warn!("couldnt connect to evicted replica {}", NodeId::from(replica_node_id));
|
||||
}
|
||||
}
|
||||
let group_name = format!("{}", ToHex(&group_id.id));
|
||||
self.partitions.insert(group_id, Partition {
|
||||
remote_group: RemoteGroupState::new(group_name, remotes),
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
fn start_replica_remote(&mut self, node_id: NodeId, group_id: RaftGroupId) -> Option<&Replica> {
|
||||
match self.replicas.start_peer(node_id, NodeType::Replica, RemoteAuthorizationType::RemoteOnly) {
|
||||
Ok(replica_entry) => {
|
||||
match replica_entry.connect(|remote| Replica { remote, group_id }) {
|
||||
Ok(replica) => Some(replica),
|
||||
Err((replica_entry, mapper)) => {
|
||||
warn!("inserting disconnected replica entry for {} due to connect error",
|
||||
replica_entry.remote().id());
|
||||
Some(replica_entry.insert(mapper))
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(Some(replica)) => Some(replica),
|
||||
Err(None) => None,
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// untrusted messages
|
||||
//
|
||||
|
||||
pub fn untrusted_message(&mut self, untrusted_message: UntrustedMessage) {
|
||||
match untrusted_message.inner {
|
||||
Some(untrusted_message::Inner::StartFrontendRequest(_)) |
|
||||
Some(untrusted_message::Inner::StartReplicaRequest(_)) =>
|
||||
(),
|
||||
|
||||
Some(untrusted_message::Inner::StartReplicaGroupRequest(_)) =>
|
||||
(),
|
||||
Some(untrusted_message::Inner::UntrustedTransactionRequest(request)) =>
|
||||
self.handle_untrusted_transaction_request(request),
|
||||
Some(untrusted_message::Inner::UntrustedXferRequest(_)) =>
|
||||
(),
|
||||
Some(untrusted_message::Inner::GetEnclaveStatusRequest(request)) =>
|
||||
self.handle_get_enclave_status_request(request),
|
||||
|
||||
Some(untrusted_message::Inner::GetQeInfoReply(reply)) =>
|
||||
self.handle_get_qe_info_reply(reply),
|
||||
Some(untrusted_message::Inner::GetQuoteReply(reply)) =>
|
||||
self.handle_get_quote_reply(reply),
|
||||
Some(untrusted_message::Inner::GetAttestationReply(reply)) =>
|
||||
self.handle_get_attestation_reply(reply),
|
||||
|
||||
Some(untrusted_message::Inner::NewMessageSignal(signal)) =>
|
||||
self.handle_new_message_signal(signal),
|
||||
Some(untrusted_message::Inner::TimerTickSignal(signal)) =>
|
||||
self.handle_timer_tick_signal(signal),
|
||||
Some(untrusted_message::Inner::SetFrontendConfigSignal(signal)) =>
|
||||
self.handle_set_frontend_config_signal(signal),
|
||||
Some(untrusted_message::Inner::SetReplicaConfigSignal(_)) =>
|
||||
(),
|
||||
Some(untrusted_message::Inner::ResetPeerSignal(signal)) =>
|
||||
self.handle_reset_peer_signal(signal),
|
||||
Some(untrusted_message::Inner::SetVerboseLoggingSignal(signal)) =>
|
||||
self.handle_set_verbose_logging_signal(signal),
|
||||
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_untrusted_transaction_request(&mut self, request: UntrustedTransactionRequest) {
|
||||
let from = PendingRequestFrom::Untrusted {
|
||||
untrusted_request_id: request.request_id,
|
||||
};
|
||||
match validate_untrusted_transaction_request(request.data) {
|
||||
Ok(transaction_request_data) => {
|
||||
self.request_transaction(transaction_request_data, from);
|
||||
}
|
||||
Err(()) => {
|
||||
error!("received invalid untrusted transaction request");
|
||||
self.cancel_pending_request(from);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_get_enclave_status_request(&mut self, request: GetEnclaveStatusRequest) {
|
||||
let memory_status = if request.memory_status {
|
||||
Some(memory_status())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mut partitions = Vec::with_capacity(self.partitions.len());
|
||||
for (group_id, partition) in &self.partitions {
|
||||
partitions.push(EnclaveFrontendPartitionStatus {
|
||||
group_id: group_id.id.clone(),
|
||||
nodes: partition.remote_group.status(),
|
||||
});
|
||||
}
|
||||
let mut ranges = Vec::with_capacity(self.key_ranges.ranges.len());
|
||||
for (range, group_id) in &self.key_ranges.ranges {
|
||||
ranges.push(EnclaveFrontendRangeStatus {
|
||||
range: range.to_pb(),
|
||||
group_id: group_id.id.clone(),
|
||||
});
|
||||
}
|
||||
kbupd_send(EnclaveMessage {
|
||||
inner: Some(enclave_message::Inner::GetEnclaveStatusReply(GetEnclaveStatusReply {
|
||||
inner: Some(get_enclave_status_reply::Inner::FrontendStatus(EnclaveFrontendStatus {
|
||||
memory_status,
|
||||
partitions,
|
||||
ranges,
|
||||
})),
|
||||
})),
|
||||
});
|
||||
}
|
||||
|
||||
fn handle_get_qe_info_reply(&mut self, reply: GetQeInfoReply) {
|
||||
self.replicas.get_qe_info_reply(reply);
|
||||
}
|
||||
|
||||
fn handle_get_quote_reply(&mut self, reply: GetQuoteReply) {
|
||||
self.replicas.get_quote_reply(reply);
|
||||
}
|
||||
|
||||
fn handle_get_attestation_reply(&mut self, reply: GetAttestationReply) {
|
||||
if let Some((Replica { remote, .. }, attestation)) = self.replicas.get_attestation_reply(reply) {
|
||||
let peer_node_id = remote.id().clone();
|
||||
self.replica_authorized(attestation, peer_node_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn replica_authorized(&mut self, _attestation: AttestationParameters, replica_node_id: NodeId) {
|
||||
if let Some((_replica, partition)) = Self::get_partition_replica_mut(&mut self.replicas, &mut self.partitions, &replica_node_id) {
|
||||
partition.remote_group.remote_authorized(&replica_node_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_new_message_signal(&mut self, signal: NewMessageSignal) {
|
||||
match self.replicas.new_message_signal(signal) {
|
||||
Ok(Some((from, message))) => {
|
||||
let from_node_id = from.remote_mut().id().clone();
|
||||
self.replica_message(message, from_node_id);
|
||||
}
|
||||
Ok(None) => (),
|
||||
Err(peer_entry) => {
|
||||
warn!("unsolicited connect request from {}: {}", peer_entry.node_id(), peer_entry.connect_request())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_timer_tick_signal(&mut self, _signal: TimerTickSignal) {
|
||||
self.replicas.timer_tick(self.config.min_connect_timeout_ticks, self.config.max_connect_timeout_ticks);
|
||||
|
||||
for partition in self.partitions.values_mut() {
|
||||
partition.remote_group.timer_tick(self.config.replica_timeout_ticks, self.config.request_quote_ticks);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_set_frontend_config_signal(&mut self, signal: SetFrontendConfigSignal) {
|
||||
info!("setting frontend config to {:#}", &signal.config);
|
||||
self.config = signal.config;
|
||||
}
|
||||
|
||||
fn handle_reset_peer_signal(&mut self, signal: ResetPeerSignal) {
|
||||
let node_id: NodeId = signal.peer_node_id.into();
|
||||
if let Some((_replica, partition)) = Self::get_partition_replica_mut(&mut self.replicas, &mut self.partitions, &node_id) {
|
||||
partition.remote_group.reset_peer(&node_id);
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_set_verbose_logging_signal(&mut self, signal: SetVerboseLoggingSignal) {
|
||||
crate::logging::set_verbose_logging_enabled(signal.verbose_logging);
|
||||
}
|
||||
|
||||
//
|
||||
// replica messages
|
||||
//
|
||||
|
||||
fn replica_message(&mut self, replica_message: ReplicaToFrontendMessage, from_node_id: NodeId) {
|
||||
match replica_message.inner {
|
||||
Some(replica_to_frontend_message::Inner::TransactionReply(transaction_reply)) =>
|
||||
self.handle_transaction_reply(transaction_reply, from_node_id),
|
||||
Some(replica_to_frontend_message::Inner::EnclaveGetQuoteReply(reply)) =>
|
||||
self.handle_enclave_get_quote_reply(reply, from_node_id),
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_transaction_reply(&mut self, transaction_reply: TransactionReply, from_node_id: NodeId) {
|
||||
if let Some((replica, partition)) = Self::get_partition_replica_mut(&mut self.replicas, &mut self.partitions, &from_node_id) {
|
||||
match transaction_reply.data {
|
||||
Some(transaction_reply::Data::ClientResponse(client_reply)) => {
|
||||
let maybe_pending_request: Option<PendingRequest> =
|
||||
partition.remote_group.handle_reply(&PendingRequestId { id: transaction_reply.request_id });
|
||||
if let Some(PendingRequestFrom::Client(pending_client_request)) =
|
||||
maybe_pending_request.map(|pending_request| pending_request.from)
|
||||
{
|
||||
pending_client_request.reply(&client_reply);
|
||||
} else {
|
||||
info!("pending client request {} not found", transaction_reply.request_id);
|
||||
}
|
||||
}
|
||||
Some(transaction_reply::Data::InvalidRequest(_invalid_request_error)) => {
|
||||
error!("replica {} reported InvalidRequest {}", &from_node_id, &transaction_reply.request_id);
|
||||
let maybe_pending_request: Option<PendingRequest> =
|
||||
partition.remote_group.handle_reply(&PendingRequestId { id: transaction_reply.request_id });
|
||||
if let Some(pending_request) = maybe_pending_request {
|
||||
self.cancel_pending_request(pending_request.from);
|
||||
}
|
||||
}
|
||||
Some(transaction_reply::Data::InternalError(_internal_error)) => {
|
||||
warn!("replica {} reported InternalError on request {}!",
|
||||
&from_node_id, &transaction_reply.request_id);
|
||||
let maybe_pending_request: Option<PendingRequest> =
|
||||
partition.remote_group.handle_reply(&PendingRequestId { id: transaction_reply.request_id });
|
||||
if let Some(pending_request) = maybe_pending_request {
|
||||
self.cancel_pending_request(pending_request.from);
|
||||
}
|
||||
}
|
||||
Some(transaction_reply::Data::CreateBackupReply(create_backup_reply)) => {
|
||||
let maybe_pending_request: Option<PendingRequest> =
|
||||
partition.remote_group.handle_reply(&PendingRequestId { id: transaction_reply.request_id });
|
||||
if let Some(PendingRequestFrom::Untrusted { untrusted_request_id }) =
|
||||
maybe_pending_request.map(|pending_request| pending_request.from)
|
||||
{
|
||||
kbupd_send(EnclaveMessage {
|
||||
inner: Some(enclave_message::Inner::UntrustedTransactionReply(UntrustedTransactionReply {
|
||||
request_id: untrusted_request_id,
|
||||
data: Some(untrusted_transaction_reply::Data::CreateBackupReply(create_backup_reply)),
|
||||
})),
|
||||
});
|
||||
} else {
|
||||
info!("pending untrusted transaction request {} not found",
|
||||
transaction_reply.request_id);
|
||||
}
|
||||
}
|
||||
Some(transaction_reply::Data::DeleteBackupReply(delete_backup_reply)) => {
|
||||
let maybe_pending_request: Option<PendingRequest> =
|
||||
partition.remote_group.handle_reply(&PendingRequestId { id: transaction_reply.request_id });
|
||||
match maybe_pending_request.map(|pending_request| pending_request.from) {
|
||||
Some(PendingRequestFrom::Client(pending_client_request)) => {
|
||||
pending_client_request.reply(&kbupd_client::Response {
|
||||
backup: None,
|
||||
restore: None,
|
||||
delete: Some(kbupd_client::DeleteResponse {}),
|
||||
});
|
||||
}
|
||||
Some(PendingRequestFrom::Untrusted { untrusted_request_id }) => {
|
||||
kbupd_send(EnclaveMessage {
|
||||
inner: Some(enclave_message::Inner::UntrustedTransactionReply(UntrustedTransactionReply {
|
||||
request_id: untrusted_request_id,
|
||||
data: Some(untrusted_transaction_reply::Data::DeleteBackupReply(delete_backup_reply)),
|
||||
})),
|
||||
});
|
||||
}
|
||||
None => {
|
||||
info!("pending client request {} not found", transaction_reply.request_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(transaction_reply::Data::NotLeader(not_leader_error_data)) => {
|
||||
let new_leader: Option<NodeId> = not_leader_error_data.leader_node_id.map(NodeId::from);
|
||||
partition.remote_group.remote_not_leader(not_leader_error_data.term, new_leader.as_ref(), &from_node_id);
|
||||
verbose!("replica {} reported NotLeader for partition {} with new leader {} at term {}",
|
||||
replica.remote.id(), &replica.group_id, OptionDisplay(new_leader.as_ref()),
|
||||
¬_leader_error_data.term);
|
||||
}
|
||||
Some(transaction_reply::Data::WrongPartition(wrong_partition_error_data)) => {
|
||||
let maybe_pending_request: Option<PendingRequest> =
|
||||
partition.remote_group.handle_reply(&PendingRequestId { id: transaction_reply.request_id });
|
||||
if let Some(range) = &wrong_partition_error_data.range {
|
||||
match PartitionKeyRange::try_from_pb(range) {
|
||||
Ok(range) => {
|
||||
info!("partition {} reported WrongPartition with range {}", &replica.group_id, range);
|
||||
self.key_ranges.update(&replica.group_id, range);
|
||||
}
|
||||
Err(()) => {
|
||||
error!("partition {} reported WrongPartition with invalid range {}",
|
||||
&replica.group_id, range);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
info!("partition {} reported WrongPartition with no range", &replica.group_id);
|
||||
self.key_ranges.remove(&replica.group_id);
|
||||
}
|
||||
if let Some(new_partition) = wrong_partition_error_data.new_partition {
|
||||
info!("partition {} reported WrongPartition with new partition {} and range {}",
|
||||
&replica.group_id, ToHex(&new_partition.group_id), OptionDisplay(new_partition.range.as_ref()));
|
||||
self.update_partition(new_partition);
|
||||
} else {
|
||||
warn!("partition {} reported WrongPartition but didn't know the right one!", &replica.group_id);
|
||||
}
|
||||
if let Some(pending_request) = maybe_pending_request {
|
||||
self.send_transaction_request(pending_request);
|
||||
}
|
||||
}
|
||||
Some(transaction_reply::Data::ServiceIdMismatch(_service_id_mismatch_data)) => {
|
||||
let maybe_pending_request: Option<PendingRequest> =
|
||||
partition.remote_group.handle_reply(&PendingRequestId { id: transaction_reply.request_id });
|
||||
if let Some(pending_request) = maybe_pending_request {
|
||||
warn!("partition {} reported ServiceIdMismatch");
|
||||
self.cancel_pending_request(pending_request.from);
|
||||
}
|
||||
}
|
||||
Some(transaction_reply::Data::XferInProgress(_xfer_in_progress_data)) => {
|
||||
let maybe_pending_request: Option<PendingRequest> =
|
||||
partition.remote_group.handle_reply(&PendingRequestId { id: transaction_reply.request_id });
|
||||
if let Some(pending_request) = maybe_pending_request {
|
||||
info!("partition {} reported XferInProgress for backup id {}",
|
||||
&replica.group_id, OptionDisplay(pending_request.backup_id()));
|
||||
self.cancel_pending_request(pending_request.from);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let maybe_pending_request: Option<PendingRequest> =
|
||||
partition.remote_group.handle_reply(&PendingRequestId { id: transaction_reply.request_id });
|
||||
if let Some(pending_request) = maybe_pending_request {
|
||||
self.cancel_pending_request(pending_request.from);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_enclave_get_quote_reply(&mut self, reply: EnclaveGetQuoteReply, from_node_id: NodeId) {
|
||||
self.replicas.request_attestation(reply.sgx_quote, from_node_id);
|
||||
}
|
||||
|
||||
//
|
||||
// client requests
|
||||
//
|
||||
|
||||
pub fn client_request(&mut self, data: transaction_request::Data, from: SgxsdMsgFrom) {
|
||||
self.request_transaction(data, PendingRequestFrom::Client(PendingClientRequest { from }));
|
||||
}
|
||||
|
||||
fn request_transaction(&mut self, data: transaction_request::Data, from: PendingRequestFrom) {
|
||||
let id = self.last_request_id.clone() + 1;
|
||||
self.last_request_id = id.clone();
|
||||
let min_attestation = match &data {
|
||||
transaction_request::Data::Create(_) |
|
||||
transaction_request::Data::Delete(_) => {
|
||||
None
|
||||
}
|
||||
transaction_request::Data::Backup(BackupTransactionRequest { valid_from, .. }) |
|
||||
transaction_request::Data::Restore(RestoreTransactionRequest { valid_from, .. }) => {
|
||||
Some(AttestationParameters::new(Duration::from_secs(*valid_from)))
|
||||
}
|
||||
};
|
||||
let message = Rc::new(FrontendToReplicaMessage {
|
||||
inner: Some(frontend_to_replica_message::Inner::TransactionRequest(TransactionRequest {
|
||||
request_id: id.id,
|
||||
data: Some(data),
|
||||
})),
|
||||
});
|
||||
let pending_request = PendingRequest {
|
||||
id,
|
||||
message,
|
||||
min_attestation,
|
||||
from,
|
||||
};
|
||||
self.send_transaction_request(pending_request);
|
||||
}
|
||||
|
||||
fn send_transaction_request(&mut self, mut pending_request: PendingRequest) {
|
||||
let Self { partitions, .. } = self;
|
||||
|
||||
if pending_request.id != self.last_request_id {
|
||||
pending_request.id = self.last_request_id.clone() + 1;
|
||||
self.last_request_id = pending_request.id.clone();
|
||||
match &mut Rc::make_mut(&mut pending_request.message).inner {
|
||||
Some(frontend_to_replica_message::Inner::TransactionRequest(txn_request)) => {
|
||||
txn_request.request_id = pending_request.id.id;
|
||||
}
|
||||
Some(frontend_to_replica_message::Inner::EnclaveGetQuoteRequest(_)) |
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(backup_id) = pending_request.backup_id() {
|
||||
let maybe_group_id: Option<&RaftGroupId> = self.key_ranges.find(backup_id);
|
||||
let maybe_partition: Option<&mut Partition> = maybe_group_id.and_then(|group_id| partitions.get_mut(group_id));
|
||||
if let Some(partition) = maybe_partition {
|
||||
let trimmed = partition.remote_group.trim_to(self.config.pending_request_count.saturating_sub(1).to_usize(),
|
||||
self.config.pending_request_ttl);
|
||||
if trimmed.len() != 0 {
|
||||
info!("dropping {} old pending requests for partition {}", trimmed.len(), partition.remote_group.name());
|
||||
}
|
||||
|
||||
if partition.remote_group.pending_len() < self.config.pending_request_count.to_usize() {
|
||||
match partition.remote_group.send(pending_request) {
|
||||
Ok(()) => (),
|
||||
Err(RemoteGroupSendError::NotYetValid(pending_request)) => {
|
||||
reject_pending_request_not_yet_valid(pending_request);
|
||||
}
|
||||
Err(RemoteGroupSendError::AlreadySent(pending_request)) => {
|
||||
warn!("dropping already sent request {}", &pending_request.id.id);
|
||||
self.cancel_pending_request(pending_request.from);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.cancel_pending_request(pending_request.from);
|
||||
}
|
||||
|
||||
for trimmed_pending_request in trimmed {
|
||||
self.cancel_pending_request(trimmed_pending_request.from)
|
||||
}
|
||||
} else {
|
||||
warn!("dropping request for missing partition of {}", backup_id);
|
||||
self.cancel_pending_request(pending_request.from);
|
||||
}
|
||||
} else {
|
||||
self.cancel_pending_request(pending_request.from);
|
||||
}
|
||||
}
|
||||
|
||||
fn cancel_pending_request(&mut self, from: PendingRequestFrom) {
|
||||
match from {
|
||||
PendingRequestFrom::Untrusted { untrusted_request_id } => {
|
||||
kbupd_send(EnclaveMessage {
|
||||
inner: Some(enclave_message::Inner::UntrustedTransactionReply(UntrustedTransactionReply {
|
||||
request_id: untrusted_request_id,
|
||||
data: None,
|
||||
})),
|
||||
});
|
||||
}
|
||||
PendingRequestFrom::Client(pending_client_request) => {
|
||||
drop(pending_client_request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_partition_replica_mut<'a, 'b>(replicas: &'a mut PeerManager<Replica>,
|
||||
partitions: &'b mut HashMap<RaftGroupId, Partition, DefaultHasher>,
|
||||
node_id: &NodeId)
|
||||
-> Option<(&'a mut Replica, &'b mut Partition)> {
|
||||
let replica = replicas.get_peer_mut(node_id)?;
|
||||
let partition = partitions.get_mut(&replica.group_id)?;
|
||||
Some((replica, partition))
|
||||
}
|
||||
|
||||
pub fn decode_request(request_type: u32, backup_id: Vec<u8>, request_data: &[u8]) -> Result<transaction_request::Data, ()> {
|
||||
let request = kbupd_client::Request::decode(request_data).map_err(|_| ())?;
|
||||
let backup_id = BackupId::try_from_slice(&backup_id)?;
|
||||
match request {
|
||||
kbupd_client::Request {
|
||||
backup: Some(backup_request),
|
||||
restore: None,
|
||||
delete: None,
|
||||
} => {
|
||||
match request_type {
|
||||
KBUPD_REQUEST_TYPE_ANY |
|
||||
KBUPD_REQUEST_TYPE_BACKUP => {
|
||||
Self::validate_backup_request(backup_id, backup_request)
|
||||
}
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
kbupd_client::Request {
|
||||
backup: None,
|
||||
restore: Some(restore_request),
|
||||
delete: None,
|
||||
} => {
|
||||
match request_type {
|
||||
KBUPD_REQUEST_TYPE_ANY |
|
||||
KBUPD_REQUEST_TYPE_RESTORE => {
|
||||
Self::validate_restore_request(backup_id, restore_request)
|
||||
}
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
kbupd_client::Request {
|
||||
backup: None,
|
||||
restore: None,
|
||||
delete: Some(delete_request),
|
||||
} => {
|
||||
match request_type {
|
||||
KBUPD_REQUEST_TYPE_ANY |
|
||||
KBUPD_REQUEST_TYPE_DELETE => {
|
||||
Self::validate_delete_request(backup_id, delete_request)
|
||||
}
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_backup_request(backup_id: BackupId, mut request: kbupd_client::BackupRequest) -> Result<transaction_request::Data, ()> {
|
||||
if let kbupd_client::BackupRequest {
|
||||
service_id,
|
||||
backup_id: Some(request_backup_id),
|
||||
nonce: Some(nonce),
|
||||
valid_from: Some(valid_from),
|
||||
data: Some(data),
|
||||
pin: Some(pin),
|
||||
tries: Some(tries),
|
||||
} = &mut request {
|
||||
if (Self::validate_request_service_id(service_id) &&
|
||||
request_backup_id == &backup_id.id &&
|
||||
nonce.len() == 32 &&
|
||||
data.len() == 32 &&
|
||||
pin.len() == 32 &&
|
||||
*tries != 0 && *tries <= u16::max_value().into())
|
||||
{
|
||||
Ok(transaction_request::Data::Backup(BackupTransactionRequest {
|
||||
service_id: service_id.take(),
|
||||
backup_id,
|
||||
nonce: std::mem::replace(nonce, Vec::new()),
|
||||
valid_from: *valid_from,
|
||||
data: SecretBytes { data: std::mem::replace(data, Vec::new()) },
|
||||
pin: SecretBytes { data: std::mem::replace(pin, Vec::new()) },
|
||||
tries: *tries,
|
||||
}))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_restore_request(backup_id: BackupId, mut request: kbupd_client::RestoreRequest) -> Result<transaction_request::Data, ()> {
|
||||
if let kbupd_client::RestoreRequest {
|
||||
service_id,
|
||||
backup_id: Some(request_backup_id),
|
||||
nonce: Some(nonce),
|
||||
valid_from: Some(valid_from),
|
||||
pin: Some(pin),
|
||||
} = &mut request {
|
||||
if (Self::validate_request_service_id(service_id) &&
|
||||
request_backup_id == &backup_id.id &&
|
||||
nonce.len() == 32 &&
|
||||
pin.len() == 32)
|
||||
{
|
||||
Ok(transaction_request::Data::Restore(RestoreTransactionRequest {
|
||||
service_id: service_id.take(),
|
||||
backup_id,
|
||||
valid_from: *valid_from,
|
||||
nonce: std::mem::replace(nonce, Vec::new()),
|
||||
pin: SecretBytes { data: std::mem::replace(pin, Vec::new()), },
|
||||
}))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_delete_request(backup_id: BackupId, request: kbupd_client::DeleteRequest) -> Result<transaction_request::Data, ()> {
|
||||
if let kbupd_client::DeleteRequest {
|
||||
service_id,
|
||||
backup_id: Some(request_backup_id),
|
||||
} = request {
|
||||
if (Self::validate_request_service_id(&service_id) &&
|
||||
request_backup_id == backup_id.id)
|
||||
{
|
||||
Ok(transaction_request::Data::Delete(DeleteTransactionRequest {
|
||||
service_id,
|
||||
backup_id,
|
||||
}))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
fn validate_request_service_id(maybe_service_id: &Option<Vec<u8>>) -> bool {
|
||||
if let Some(service_id) = maybe_service_id {
|
||||
service_id.len() == 32
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn reject_pending_request_not_yet_valid(pending_request: PendingRequest) {
|
||||
match pending_request.from {
|
||||
PendingRequestFrom::Client(pending_client_request) => {
|
||||
info!("rejecting not yet valid client request {} requiring {}",
|
||||
&pending_request.id.id, OptionDisplay(pending_request.min_attestation.as_ref()));
|
||||
match &pending_request.message.as_ref().inner {
|
||||
Some(frontend_to_replica_message::Inner::TransactionRequest(TransactionRequest { data, .. })) => {
|
||||
match data {
|
||||
Some(transaction_request::Data::Backup(_)) => {
|
||||
pending_client_request.reply(&kbupd_client::Response {
|
||||
backup: Some(kbupd_client::BackupResponse {
|
||||
status: Some(kbupd_client::backup_response::Status::NotYetValid.into()),
|
||||
nonce: None,
|
||||
}),
|
||||
restore: None,
|
||||
delete: None,
|
||||
});
|
||||
}
|
||||
Some(transaction_request::Data::Restore(_)) => {
|
||||
pending_client_request.reply(&kbupd_client::Response {
|
||||
backup: None,
|
||||
restore: Some(kbupd_client::RestoreResponse {
|
||||
status: Some(kbupd_client::restore_response::Status::NotYetValid.into()),
|
||||
nonce: None,
|
||||
data: None,
|
||||
tries: None,
|
||||
}),
|
||||
delete: None,
|
||||
});
|
||||
}
|
||||
Some(transaction_request::Data::Create(_)) |
|
||||
Some(transaction_request::Data::Delete(_)) |
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
Some(frontend_to_replica_message::Inner::EnclaveGetQuoteRequest(_)) |
|
||||
None => (),
|
||||
}
|
||||
}
|
||||
PendingRequestFrom::Untrusted { untrusted_request_id } => {
|
||||
info!("rejecting not yet valid untrusted request {} requiring {}",
|
||||
untrusted_request_id, OptionDisplay(pending_request.min_attestation.as_ref()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// PartitionKeyRanges impls
|
||||
//
|
||||
|
||||
impl PartitionKeyRanges {
|
||||
fn range_cmp(one: &PartitionKeyRange, two: &PartitionKeyRange) -> Ordering {
|
||||
(one.first(), one.last()).cmp(&(two.first(), two.last()))
|
||||
}
|
||||
fn entry_cmp(one: &(PartitionKeyRange, RaftGroupId), two: &(PartitionKeyRange, RaftGroupId)) -> Ordering {
|
||||
Self::range_cmp(&one.0, &two.0)
|
||||
}
|
||||
fn key_cmp(range: &PartitionKeyRange, key: &BackupId) -> Ordering {
|
||||
match range.first().as_ref().cmp(&key.id) {
|
||||
Ordering::Greater => Ordering::Greater,
|
||||
Ordering::Less |
|
||||
Ordering::Equal => {
|
||||
match range.last().as_ref().cmp(&key.id) {
|
||||
Ordering::Less => Ordering::Less,
|
||||
Ordering::Greater |
|
||||
Ordering::Equal => Ordering::Equal,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fn update(&mut self, update_group_id: &RaftGroupId, update_range: PartitionKeyRange) {
|
||||
let mut matches =
|
||||
self.ranges.iter_mut()
|
||||
.filter(|(_, group_id)| group_id == update_group_id)
|
||||
.peekable();
|
||||
if matches.peek().is_none() {
|
||||
match self.ranges[..].binary_search_by(|(range, _)| Self::range_cmp(range, &update_range))
|
||||
.and_then(|ranges_index| self.ranges.get_mut(ranges_index).ok_or(ranges_index))
|
||||
{
|
||||
Ok((_, group_id)) => {
|
||||
*group_id = update_group_id.clone();
|
||||
}
|
||||
Err(ranges_index) => {
|
||||
self.ranges.insert(ranges_index, (update_range, update_group_id.clone()));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (range, _) in matches {
|
||||
*range = update_range;
|
||||
}
|
||||
}
|
||||
self.ranges[..].sort_unstable_by(Self::entry_cmp);
|
||||
}
|
||||
fn remove(&mut self, remove_group_id: &RaftGroupId) {
|
||||
self.ranges.retain(|(_range, group_id)| group_id != remove_group_id);
|
||||
}
|
||||
fn find<'a>(&'a self, key: &BackupId) -> Option<&'a RaftGroupId> {
|
||||
self.ranges[..]
|
||||
.binary_search_by(|(range, _)| Self::key_cmp(range, key))
|
||||
.ok()
|
||||
.and_then(|ranges_index| self.ranges.get(ranges_index))
|
||||
.filter(|(range, _group_id)| range.contains_id(key))
|
||||
.map(|(_range, group_id)| group_id)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// PendingRequestId impls
|
||||
//
|
||||
|
||||
impl Add<u64> for PendingRequestId {
|
||||
type Output = Self;
|
||||
fn add(self, inc: u64) -> Self {
|
||||
Self { id: self.id.checked_add(inc).unwrap_or_else(|| panic!("overflow")) }
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// PendingRequest impls
|
||||
//
|
||||
|
||||
impl PendingRequest {
|
||||
fn backup_id(&self) -> Option<&BackupId> {
|
||||
if let Some(frontend_to_replica_message::Inner::TransactionRequest(TransactionRequest { data: Some(data), .. })) = &self.message.inner {
|
||||
match data {
|
||||
transaction_request::Data::Create(create_request) => Some(&create_request.backup_id),
|
||||
transaction_request::Data::Backup(backup_request) => Some(&backup_request.backup_id),
|
||||
transaction_request::Data::Restore(restore_request) => Some(&restore_request.backup_id),
|
||||
transaction_request::Data::Delete(delete_request) => Some(&delete_request.backup_id),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RemoteGroupPendingRequest for PendingRequest {
|
||||
type RequestId = PendingRequestId;
|
||||
type Message = FrontendToReplicaMessage;
|
||||
fn request_id(&self) -> &Self::RequestId {
|
||||
&self.id
|
||||
}
|
||||
fn message(&self) -> Rc<Self::Message> {
|
||||
Rc::clone(&self.message)
|
||||
}
|
||||
fn min_attestation(&self) -> Option<AttestationParameters> {
|
||||
self.min_attestation
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// PendingClientRequest impls
|
||||
//
|
||||
|
||||
impl PendingClientRequest {
|
||||
pub fn reply(self, reply: &kbupd_client::Response) {
|
||||
let mut data = SecretValue::new(Vec::with_capacity(reply.encoded_len()));
|
||||
match reply.encode(data.get_mut()) {
|
||||
Ok(()) => (),
|
||||
Err(_) => {
|
||||
error!("error encoding client reply");
|
||||
return;
|
||||
}
|
||||
}
|
||||
match self.from.reply(data.get_mut()) {
|
||||
Ok(()) => {
|
||||
// no need to erase, as SgxsdFrom::reply encrypts in-place
|
||||
data.get_mut().clear();
|
||||
}
|
||||
Err(sgx_status) => {
|
||||
error!("error replying to client request: {}", sgx_status);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Replica impls
|
||||
//
|
||||
|
||||
impl Peer for Replica {
|
||||
type Message = ReplicaToFrontendMessage;
|
||||
fn remote_mut(&mut self) -> &mut dyn Remote {
|
||||
&mut self.remote
|
||||
}
|
||||
fn recv(&mut self, msg_data: &[u8]) -> Result<Self::Message, RemoteRecvError> {
|
||||
self.remote.recv(msg_data)
|
||||
}
|
||||
fn send_quote_reply(&mut self, _reply: EnclaveGetQuoteReply) -> Result<(), ()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// RemoteSender impls
|
||||
//
|
||||
|
||||
impl RemoteGroupNode for RemoteSender<FrontendToReplicaMessage> {
|
||||
fn request_quote(&mut self, request: EnclaveGetQuoteRequest) -> Result<(), ()> {
|
||||
self.send(Rc::new(FrontendToReplicaMessage {
|
||||
inner: Some(frontend_to_replica_message::Inner::EnclaveGetQuoteRequest(request)),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// internal
|
||||
//
|
||||
|
||||
fn validate_untrusted_transaction_request(request_data: Option<untrusted_transaction_request::Data>)
|
||||
-> Result<transaction_request::Data, ()> {
|
||||
match request_data {
|
||||
Some(untrusted_transaction_request::Data::CreateBackupRequest(create_backup_request)) => {
|
||||
if create_backup_request.backup_id.id.len() == 32 {
|
||||
Ok(transaction_request::Data::Create(create_backup_request))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
Some(untrusted_transaction_request::Data::DeleteBackupRequest(delete_backup_request)) => {
|
||||
if delete_backup_request.backup_id.id.len() == 32 {
|
||||
Ok(transaction_request::Data::Delete(DeleteTransactionRequest {
|
||||
service_id: None,
|
||||
backup_id: delete_backup_request.backup_id,
|
||||
}))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
None => Err(()),
|
||||
}
|
||||
}
|
||||
145
enclave/kbupd_enclave/src/service/main.rs
Normal file
145
enclave/kbupd_enclave/src/service/main.rs
Normal file
@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
use std::cell::*;
|
||||
|
||||
use sgx_ffi::sgx::*;
|
||||
use sgxsd_ffi::ecalls::*;
|
||||
|
||||
use crate::ffi::ecalls::*;
|
||||
use crate::protobufs::kbupd::*;
|
||||
use crate::protobufs::kbupd::untrusted_message;
|
||||
use crate::service::frontend::*;
|
||||
use crate::service::replica::*;
|
||||
|
||||
//
|
||||
// public api
|
||||
//
|
||||
|
||||
#[allow(variant_size_differences)]
|
||||
pub enum ServiceState {
|
||||
NotStarted,
|
||||
Frontend(FrontendState),
|
||||
Replica(ReplicaState),
|
||||
}
|
||||
|
||||
pub struct SgxsdState {
|
||||
}
|
||||
|
||||
#[cfg(not(any(test, feature = "test")))]
|
||||
pub fn whereis<F, R>(fun: F) -> R
|
||||
where F: FnOnce(&RefCell<ServiceState>) -> R
|
||||
{
|
||||
#[thread_local]
|
||||
static SERVICE: RefCell<ServiceState> = RefCell::new(ServiceState::NotStarted);
|
||||
|
||||
fun(&SERVICE)
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test"))]
|
||||
pub fn whereis<F, R>(fun: F) -> R
|
||||
where F: FnOnce(&RefCell<ServiceState>) -> R
|
||||
{
|
||||
thread_local! {
|
||||
static SERVICE: RefCell<ServiceState> = RefCell::new(ServiceState::NotStarted);
|
||||
}
|
||||
|
||||
SERVICE.with(fun)
|
||||
}
|
||||
|
||||
//
|
||||
// ServiceState impls
|
||||
//
|
||||
|
||||
impl KbupdService for ServiceState {
|
||||
fn untrusted_message(&mut self, msg: UntrustedMessage) {
|
||||
match msg.inner {
|
||||
Some(untrusted_message::Inner::StartFrontendRequest(start_frontend_req)) => {
|
||||
if let ServiceState::NotStarted = self {
|
||||
*self = ServiceState::Frontend(FrontendState::init(start_frontend_req));
|
||||
} else {
|
||||
warn!("node service already started");
|
||||
}
|
||||
}
|
||||
Some(untrusted_message::Inner::StartReplicaRequest(start_replica_req)) => {
|
||||
if let ServiceState::NotStarted = self {
|
||||
*self = ServiceState::Replica(ReplicaState::init(start_replica_req));
|
||||
} else {
|
||||
warn!("node service already started");
|
||||
}
|
||||
}
|
||||
Some(_) => {
|
||||
match self {
|
||||
ServiceState::Replica(replica) => {
|
||||
replica.untrusted_message(msg);
|
||||
}
|
||||
ServiceState::Frontend(frontend) => {
|
||||
frontend.untrusted_message(msg);
|
||||
}
|
||||
ServiceState::NotStarted => {
|
||||
warn!("node service not started");
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SgxsdServer for SgxsdState {
|
||||
type InitArgs = StartArgs;
|
||||
type HandleCallArgs = CallArgs;
|
||||
type TerminateArgs = StopArgs;
|
||||
|
||||
fn init(_args: Option<&Self::InitArgs>) -> Result<Self, SgxStatus> {
|
||||
Ok(Self {})
|
||||
}
|
||||
|
||||
fn handle_call(&mut self,
|
||||
args: Option<&Self::HandleCallArgs>,
|
||||
request_data: &[u8],
|
||||
from: SgxsdMsgFrom)
|
||||
-> Result<(), (SgxStatus, SgxsdMsgFrom)>
|
||||
{
|
||||
let args = match args {
|
||||
Some(args) => args,
|
||||
None => return Err((SGX_ERROR_INVALID_PARAMETER, from)),
|
||||
};
|
||||
match FrontendState::decode_request(args.request_type, args.backup_id.to_vec(), request_data) {
|
||||
Ok(request) => {
|
||||
whereis(|service_ref| {
|
||||
let mut service = service_ref.borrow_mut();
|
||||
if let ServiceState::Frontend(frontend) = &mut *service {
|
||||
frontend.client_request(request, from);
|
||||
Ok(())
|
||||
} else {
|
||||
warn!("frontend service not started");
|
||||
Err((SGX_ERROR_INVALID_STATE, from))
|
||||
}
|
||||
})
|
||||
}
|
||||
Err(()) => {
|
||||
Err((SGX_ERROR_INVALID_PARAMETER, from))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn terminate(self, _args: Option<&Self::TerminateArgs>) -> Result<(), SgxStatus> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
20
enclave/kbupd_enclave/src/service/mod.rs
Normal file
20
enclave/kbupd_enclave/src/service/mod.rs
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
pub mod main;
|
||||
pub mod frontend;
|
||||
pub mod replica;
|
||||
1472
enclave/kbupd_enclave/src/service/replica/mod.rs
Normal file
1472
enclave/kbupd_enclave/src/service/replica/mod.rs
Normal file
File diff suppressed because it is too large
Load Diff
1214
enclave/kbupd_enclave/src/service/replica/partition_data.rs
Normal file
1214
enclave/kbupd_enclave/src/service/replica/partition_data.rs
Normal file
File diff suppressed because it is too large
Load Diff
564
enclave/kbupd_enclave/src/service/replica/partition_key_range.rs
Normal file
564
enclave/kbupd_enclave/src/service/replica/partition_key_range.rs
Normal file
@ -0,0 +1,564 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
use std::fmt;
|
||||
use std::ops::*;
|
||||
|
||||
use crate::protobufs::kbupd::*;
|
||||
use crate::util::*;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialOrd, Ord)]
|
||||
pub struct PartitionKey([u8; 32]);
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||
pub struct PartitionKeyRange {
|
||||
first: PartitionKey,
|
||||
last: PartitionKey,
|
||||
}
|
||||
|
||||
//
|
||||
// PartittionKeyRange impls
|
||||
//
|
||||
|
||||
impl PartitionKeyRange {
|
||||
pub fn new(first: PartitionKey, last: PartitionKey) -> Result<Self, ()> {
|
||||
if first <= last {
|
||||
Ok(Self { first, last })
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_unbounded() -> Self {
|
||||
Self {
|
||||
first: PartitionKey::new([0x00; 32]),
|
||||
last: PartitionKey::new([0xFF; 32]),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_from_pb(pb: &PartitionKeyRangePb) -> Result<Self, ()> {
|
||||
Self::from_ids(&pb.first, &pb.last)
|
||||
}
|
||||
|
||||
fn from_ids(first: &BackupId, last: &BackupId) -> Result<Self, ()> {
|
||||
Self::new(PartitionKey::try_from_pb(first)?, PartitionKey::try_from_pb(last)?)
|
||||
}
|
||||
|
||||
pub fn to_pb(&self) -> PartitionKeyRangePb {
|
||||
PartitionKeyRangePb {
|
||||
first: BackupId { id: self.first.to_vec() },
|
||||
last: BackupId { id: self.last.to_vec() },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn first(&self) -> &PartitionKey {
|
||||
&self.first
|
||||
}
|
||||
|
||||
pub fn last(&self) -> &PartitionKey {
|
||||
&self.last
|
||||
}
|
||||
|
||||
pub fn contains(&self, key: &[u8; 32]) -> bool {
|
||||
(key >= &self.first &&
|
||||
key <= &self.last)
|
||||
}
|
||||
|
||||
pub fn contains_id(&self, key: &BackupId) -> bool {
|
||||
let mut id: [u8; 32] = Default::default();
|
||||
if key.id.len() == id.len() {
|
||||
id.copy_from_slice(&key.id);
|
||||
self.contains(&id)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains_range(&self, other: &Self) -> bool {
|
||||
self.contains(&other.first) && self.contains(&other.last)
|
||||
}
|
||||
|
||||
pub fn overlaps_range(&self, other: &Self) -> bool {
|
||||
(self.contains(&other.first) || self.contains(&other.last) ||
|
||||
other.contains(&self.first) || other.contains(&self.last))
|
||||
}
|
||||
|
||||
pub fn split_off_inclusive(&mut self, new_last: &PartitionKey) -> Result<Option<Self>, ()> {
|
||||
if self.contains(new_last) {
|
||||
if let Some(other_first) = new_last.checked_add(1) {
|
||||
let other_last = std::mem::replace(&mut self.last, *new_last);
|
||||
Ok(Self::new(other_first, other_last).ok())
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RangeBounds<PartitionKey> for &PartitionKeyRange {
|
||||
fn start_bound(&self) -> Bound<&PartitionKey> {
|
||||
Bound::Included(&self.first)
|
||||
}
|
||||
fn end_bound(&self) -> Bound<&PartitionKey> {
|
||||
Bound::Included(&self.last)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for PartitionKeyRange {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
fmt::Display::fmt(self, fmt)
|
||||
}
|
||||
}
|
||||
impl fmt::Display for PartitionKeyRange {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
let Self { first, last } = self;
|
||||
write!(fmt, "{}-{}", first, last)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// PartitionKey impls
|
||||
//
|
||||
|
||||
impl PartitionKey {
|
||||
pub fn new(value: [u8; 32]) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
|
||||
pub fn try_from_pb(backup_id: &BackupId) -> Result<Self, ()> {
|
||||
let mut value = [0u8; 32];
|
||||
if backup_id.id.len() == value.len() {
|
||||
value.copy_from_slice(&backup_id.id);
|
||||
Ok(Self(value))
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_pb(&self) -> BackupId {
|
||||
BackupId {
|
||||
id: self.0.to_vec(),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::indexing_slicing, clippy::integer_arithmetic)]
|
||||
pub fn checked_sub(&self, rhs: u8) -> Option<Self> {
|
||||
let mut ret = [0x00; 32];
|
||||
let mut carry = rhs;
|
||||
for (i, b) in self.0.iter().rev().enumerate() {
|
||||
let new_b = b.overflowing_sub(carry);
|
||||
carry = if new_b.1 { 1 } else { 0 };
|
||||
ret[31 - i] = new_b.0;
|
||||
}
|
||||
if carry == 0 {
|
||||
Some(Self(ret))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
#[allow(clippy::indexing_slicing, clippy::integer_arithmetic)]
|
||||
pub fn checked_add(&self, rhs: u8) -> Option<Self> {
|
||||
let mut ret = [0x00; 32];
|
||||
let mut carry = rhs;
|
||||
for (i, b) in self.0.iter().rev().enumerate() {
|
||||
let new_b = b.overflowing_add(carry);
|
||||
carry = if new_b.1 { 1 } else { 0 };
|
||||
ret[31 - i] = new_b.0;
|
||||
}
|
||||
if carry == 0 {
|
||||
Some(Self(ret))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for PartitionKey {
|
||||
type Target = [u8; 32];
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> PartialEq<T> for PartitionKey
|
||||
where T: AsRef<[u8]>
|
||||
{
|
||||
fn eq(&self, other: &T) -> bool {
|
||||
self.0 == other.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for PartitionKey {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for PartitionKey {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
fmt::Display::fmt(self, fmt)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for PartitionKey {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
let Self(key) = self;
|
||||
write!(fmt, "{}", ToHex(key))
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// tests
|
||||
//
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn valid_full_range() {
|
||||
PartitionKeyRange::try_from_pb(
|
||||
&PartitionKeyRange::from_ids(&BackupId { id: vec![0x00; 32] },
|
||||
&BackupId { id: vec![0xFF; 32] })
|
||||
.unwrap()
|
||||
.to_pb()
|
||||
).unwrap();
|
||||
}
|
||||
#[test]
|
||||
fn valid_empty_range() {
|
||||
PartitionKeyRange::try_from_pb(
|
||||
&PartitionKeyRange::from_ids(&BackupId { id: vec![0x00; 32] },
|
||||
&BackupId { id: vec![0x00; 32] })
|
||||
.unwrap()
|
||||
.to_pb()
|
||||
).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_inverted_range() {
|
||||
PartitionKeyRange::from_ids(&BackupId { id: vec![0xFF; 32] },
|
||||
&BackupId { id: vec![0x00; 32] })
|
||||
.unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_range_empty_first() {
|
||||
PartitionKeyRange::from_ids(&BackupId { id: vec![0x00; 0] },
|
||||
&BackupId { id: vec![0xFF; 32] })
|
||||
.unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_range_empty_last() {
|
||||
PartitionKeyRange::from_ids(&BackupId { id: vec![0x00; 32] },
|
||||
&BackupId { id: vec![0xFF; 0] })
|
||||
.unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_range_short_first() {
|
||||
PartitionKeyRange::from_ids(&BackupId { id: vec![0x00; 31] },
|
||||
&BackupId { id: vec![0xFF; 32] })
|
||||
.unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_range_short_last() {
|
||||
PartitionKeyRange::from_ids(&BackupId { id: vec![0x00; 31] },
|
||||
&BackupId { id: vec![0xFF; 32] })
|
||||
.unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_range_long_first() {
|
||||
PartitionKeyRange::from_ids(&BackupId { id: vec![0x00; 33] },
|
||||
&BackupId { id: vec![0xFF; 32] })
|
||||
.unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_range_long_last() {
|
||||
PartitionKeyRange::from_ids(&BackupId { id: vec![0x00; 32] },
|
||||
&BackupId { id: vec![0xFF; 33] })
|
||||
.unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn contains_id_valid() {
|
||||
let range = PartitionKeyRange::new_unbounded();
|
||||
assert!(range.contains_id(&BackupId { id: vec![0x00; 32] }));
|
||||
assert!(range.contains_id(&BackupId { id: vec![0xFF; 32] }));
|
||||
assert!(range.contains_id(&BackupId { id: vec![0x80; 32] }));
|
||||
|
||||
let range = PartitionKeyRange::new(PartitionKey::new([0x00; 32]), PartitionKey::new([0x80; 32])).unwrap();
|
||||
assert!(range.contains_id(&BackupId { id: vec![0x00; 32] }));
|
||||
assert!(range.contains_id(&PartitionKey::new([0x80; 32]).checked_sub(1).unwrap().to_pb()));
|
||||
assert!(range.contains_id(&BackupId { id: vec![0x80; 32] }));
|
||||
assert!(!range.contains_id(&PartitionKey::new([0x80; 32]).checked_add(1).unwrap().to_pb()));
|
||||
assert!(!range.contains_id(&BackupId { id: vec![0xFF; 32] }));
|
||||
|
||||
let range = PartitionKeyRange::new(PartitionKey::new([0xBE; 32]), PartitionKey::new([0xEF; 32])).unwrap();
|
||||
assert!(!range.contains_id(&BackupId { id: vec![0x00; 32] }));
|
||||
assert!(!range.contains_id(&PartitionKey::new([0xBE; 32]).checked_sub(1).unwrap().to_pb()));
|
||||
assert!(range.contains_id(&BackupId { id: vec![0xBE; 32] }));
|
||||
assert!(range.contains_id(&PartitionKey::new([0xBE; 32]).checked_add(1).unwrap().to_pb()));
|
||||
assert!(range.contains_id(&PartitionKey::new([0xEF; 32]).checked_sub(1).unwrap().to_pb()));
|
||||
assert!(range.contains_id(&BackupId { id: vec![0xEF; 32] }));
|
||||
assert!(!range.contains_id(&PartitionKey::new([0xEF; 32]).checked_add(1).unwrap().to_pb()));
|
||||
assert!(!range.contains_id(&BackupId { id: vec![0xFF; 32] }));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn contains_id_invalid() {
|
||||
assert!(!PartitionKeyRange::new_unbounded().contains_id(&BackupId { id: vec![] }));
|
||||
assert!(!PartitionKeyRange::new_unbounded().contains_id(&BackupId { id: vec![0x00; 31] }));
|
||||
assert!(!PartitionKeyRange::new_unbounded().contains_id(&BackupId { id: vec![0x00; 33] }));
|
||||
}
|
||||
|
||||
macro_rules! key {
|
||||
([$value:expr] + $addend:expr) => ({
|
||||
PartitionKey::new([$value; 32]).checked_add($addend)
|
||||
.unwrap_or_else(|| panic!("test key overflow"))
|
||||
});
|
||||
([$value:expr] - $subtrahend:expr) => ({
|
||||
PartitionKey::new([$value; 32]).checked_sub($subtrahend)
|
||||
.unwrap_or_else(|| panic!("test key underflow"))
|
||||
});
|
||||
([$value:expr]) => ({
|
||||
PartitionKey::new([$value; 32])
|
||||
});
|
||||
}
|
||||
|
||||
macro_rules! range {
|
||||
([$value:expr], $($second:tt)*) => (range!({key!([$value])}, $($second)*));
|
||||
([$value:expr] + $addend:expr, $($second:tt)*) => (range!({key!([$value] + $addend)}, $($second)*));
|
||||
([$value:expr] - $subtrahend:expr, $($second:tt)*) => (range!({key!([$value] - $subtrahend)}, $($second)*));
|
||||
|
||||
($first:block, [$value:expr]) => (range!($first, {key!([$value])}));
|
||||
($first:block, [$value:expr] + $addend:expr) => (range!($first, {key!([$value] + $addend)}));
|
||||
($first:block, [$value:expr] - $subtrahend:expr) => (range!($first, {key!([$value] - $subtrahend)}));
|
||||
|
||||
($first:block, $last:block) => ({
|
||||
PartitionKeyRange::new($first, $last).unwrap_or_else(|()| panic!("invalid test range"))
|
||||
});
|
||||
() => ({
|
||||
PartitionKeyRange::new_unbounded()
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn overlaps_range() {
|
||||
let range = range!();
|
||||
assert!(range.overlaps_range(&range!()));
|
||||
assert!(range.overlaps_range(&range!([0x00], [0x00])));
|
||||
assert!(range.overlaps_range(&range!([0x00], [0xBE])));
|
||||
assert!(range.overlaps_range(&range!([0xBE], [0xEF])));
|
||||
assert!(range.overlaps_range(&range!([0xEF], [0xFF])));
|
||||
assert!(range.overlaps_range(&range!([0xFF], [0xFF])));
|
||||
|
||||
let range = range!([0x00], [0xBE]);
|
||||
assert!( range.overlaps_range(&range!()));
|
||||
assert!( range.overlaps_range(&range!([0x00], [0x00])));
|
||||
assert!( range.overlaps_range(&range!([0x00], [0xBE]-1)));
|
||||
assert!( range.overlaps_range(&range!([0x00], [0xBE])));
|
||||
assert!( range.overlaps_range(&range!([0x00], [0xFF])));
|
||||
assert!( range.overlaps_range(&range!([0xBA], [0xBA])));
|
||||
assert!( range.overlaps_range(&range!([0xBA], [0xBE])));
|
||||
assert!( range.overlaps_range(&range!([0xBA], [0xBE]+1)));
|
||||
assert!( range.overlaps_range(&range!([0xBE], [0xBE])));
|
||||
assert!( range.overlaps_range(&range!([0xBE], [0xBE]+1)));
|
||||
assert!(!range.overlaps_range(&range!([0xBE]+1, [0xEF])));
|
||||
assert!(!range.overlaps_range(&range!([0xEF], [0xFF])));
|
||||
assert!(!range.overlaps_range(&range!([0xFF], [0xFF])));
|
||||
|
||||
let range = range!([0xBE], [0xEF]);
|
||||
assert!( range.overlaps_range(&range!()));
|
||||
assert!(!range.overlaps_range(&range!([0x00], [0x00])));
|
||||
assert!(!range.overlaps_range(&range!([0x00], [0xBE]-1)));
|
||||
assert!( range.overlaps_range(&range!([0x00], [0xBE])));
|
||||
assert!( range.overlaps_range(&range!([0x00], [0xBF])));
|
||||
assert!( range.overlaps_range(&range!([0x00], [0xEF])));
|
||||
assert!( range.overlaps_range(&range!([0x00], [0xEF]+1)));
|
||||
assert!( range.overlaps_range(&range!([0x00], [0xFF])));
|
||||
assert!( range.overlaps_range(&range!([0xBE], [0xEF])));
|
||||
assert!( range.overlaps_range(&range!([0xBE], [0xEF]+1)));
|
||||
assert!( range.overlaps_range(&range!([0xBE]+1, [0xEF]-1)));
|
||||
assert!( range.overlaps_range(&range!([0xBE]+1, [0xEF])));
|
||||
assert!( range.overlaps_range(&range!([0xBE]+1, [0xEF]+1)));
|
||||
assert!( range.overlaps_range(&range!([0xEF], [0xEF])));
|
||||
assert!( range.overlaps_range(&range!([0xEF], [0xEF]+1)));
|
||||
assert!(!range.overlaps_range(&range!([0xEF]+1, [0xEF]+1)));
|
||||
assert!(!range.overlaps_range(&range!([0xEF]+1, [0xFF])));
|
||||
|
||||
let range = range!([0xEF], [0xFF]);
|
||||
assert!(!range.overlaps_range(&range!([0x00], [0x00])));
|
||||
assert!(!range.overlaps_range(&range!([0x00], [0xEF]-1)));
|
||||
assert!( range.overlaps_range(&range!([0x00], [0xEF])));
|
||||
assert!( range.overlaps_range(&range!([0x00], [0xEF]+1)));
|
||||
assert!( range.overlaps_range(&range!([0x00], [0xFF])));
|
||||
assert!( range.overlaps_range(&range!([0xEF], [0xEF])));
|
||||
assert!( range.overlaps_range(&range!([0xEF], [0xEF]+1)));
|
||||
assert!( range.overlaps_range(&range!([0xEF], [0xFF])));
|
||||
assert!( range.overlaps_range(&range!([0xEF]+1, [0xFF]-1)));
|
||||
assert!( range.overlaps_range(&range!([0xEF]+1, [0xFF])));
|
||||
assert!( range.overlaps_range(&range!([0xFF], [0xFF])));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn split_off_first() {
|
||||
let mut range = PartitionKeyRange::new_unbounded();
|
||||
let split_off = range.split_off_inclusive(&PartitionKey::new([0x00; 32])).unwrap().unwrap();
|
||||
assert_eq!(range.first(), &[0x00; 32]);
|
||||
assert_eq!(range.last(), &[0x00; 32]);
|
||||
assert_eq!(split_off.first(), &range.last().checked_add(1).unwrap());
|
||||
assert_eq!(split_off.last(), &[0xff; 32]);
|
||||
|
||||
let mut range = PartitionKeyRange::new(PartitionKey::new([0xbe; 32]), PartitionKey::new([0xef; 32])).unwrap();
|
||||
let split_off = range.split_off_inclusive(&PartitionKey::new([0xbe; 32])).unwrap().unwrap();
|
||||
assert_eq!(range.first(), &[0xbe; 32]);
|
||||
assert_eq!(range.last(), &[0xbe; 32]);
|
||||
assert_eq!(split_off.first(), &range.last().checked_add(1).unwrap());
|
||||
assert_eq!(split_off.last(), &[0xef; 32]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn split_off_mid() {
|
||||
let mut range = PartitionKeyRange::new_unbounded();
|
||||
let split_off = range.split_off_inclusive(&PartitionKey::new([0x80; 32])).unwrap().unwrap();
|
||||
assert_eq!(range.first(), &[0x00; 32]);
|
||||
assert_eq!(range.last(), &[0x80; 32]);
|
||||
assert_eq!(split_off.first(), &range.last().checked_add(1).unwrap());
|
||||
assert_eq!(split_off.last(), &[0xff; 32]);
|
||||
|
||||
let mut range = PartitionKeyRange::new(PartitionKey::new([0xbe; 32]), PartitionKey::new([0xef; 32])).unwrap();
|
||||
let split_off = range.split_off_inclusive(&PartitionKey::new([0xdd; 32])).unwrap().unwrap();
|
||||
assert_eq!(range.first(), &[0xbe; 32]);
|
||||
assert_eq!(range.last(), &[0xdd; 32]);
|
||||
assert_eq!(split_off.first(), &range.last().checked_add(1).unwrap());
|
||||
assert_eq!(split_off.last(), &[0xef; 32]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn split_off_last() {
|
||||
let mut range = PartitionKeyRange::new_unbounded();
|
||||
let split_off = range.split_off_inclusive(&PartitionKey::new([0xff; 32])).unwrap();
|
||||
assert_eq!(range.first(), &[0x00; 32]);
|
||||
assert_eq!(range.last(), &[0xff; 32]);
|
||||
assert!(split_off.is_none());
|
||||
|
||||
let mut range = PartitionKeyRange::new(PartitionKey::new([0xbe; 32]), PartitionKey::new([0xef; 32])).unwrap();
|
||||
let split_off = range.split_off_inclusive(&PartitionKey::new([0xef; 32])).unwrap();
|
||||
assert_eq!(range.first(), &[0xbe; 32]);
|
||||
assert_eq!(range.last(), &[0xef; 32]);
|
||||
assert!(split_off.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn split_off_small() {
|
||||
let mut range = PartitionKeyRange::new(PartitionKey::new([0x00; 32]), PartitionKey::new([0x00; 32])).unwrap();
|
||||
let split_off = range.split_off_inclusive(&PartitionKey::new([0x00; 32])).unwrap();
|
||||
assert_eq!(range.first(), &[0x00; 32]);
|
||||
assert_eq!(range.last(), &[0x00; 32]);
|
||||
assert!(split_off.is_none());
|
||||
|
||||
let mut range = PartitionKeyRange::new(PartitionKey::new([0xbe; 32]), PartitionKey::new([0xbe; 32])).unwrap();
|
||||
let split_off = range.split_off_inclusive(&PartitionKey::new([0xbe; 32])).unwrap();
|
||||
assert_eq!(range.first(), &[0xbe; 32]);
|
||||
assert_eq!(range.last(), &[0xbe; 32]);
|
||||
assert!(split_off.is_none());
|
||||
|
||||
let mut range = PartitionKeyRange::new(PartitionKey::new([0xff; 32]), PartitionKey::new([0xff; 32])).unwrap();
|
||||
let split_off = range.split_off_inclusive(&PartitionKey::new([0xff; 32])).unwrap();
|
||||
assert_eq!(range.first(), &[0xff; 32]);
|
||||
assert_eq!(range.last(), &[0xff; 32]);
|
||||
assert!(split_off.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn split_off_err() {
|
||||
let mut range = PartitionKeyRange::new(PartitionKey::new([0x00; 32]), PartitionKey::new([0x00; 32])).unwrap();
|
||||
range.split_off_inclusive(&range.last().checked_add(1).unwrap()).unwrap_err();
|
||||
range.split_off_inclusive(&PartitionKey::new([0xff; 32])).unwrap_err();
|
||||
|
||||
let mut range = PartitionKeyRange::new(PartitionKey::new([0x00; 32]), PartitionKey::new([0xbe; 32])).unwrap();
|
||||
range.split_off_inclusive(&range.last().checked_add(1).unwrap()).unwrap_err();
|
||||
range.split_off_inclusive(&PartitionKey::new([0xbf; 32])).unwrap_err();
|
||||
range.split_off_inclusive(&PartitionKey::new([0xff; 32])).unwrap_err();
|
||||
|
||||
let mut range = PartitionKeyRange::new(PartitionKey::new([0xbe; 32]), PartitionKey::new([0xbe; 32])).unwrap();
|
||||
range.split_off_inclusive(&PartitionKey::new([0x00; 32])).unwrap_err();
|
||||
range.split_off_inclusive(&PartitionKey::new([0xba; 32])).unwrap_err();
|
||||
range.split_off_inclusive(&range.first().checked_sub(1).unwrap()).unwrap_err();
|
||||
range.split_off_inclusive(&range.last().checked_add(1).unwrap()).unwrap_err();
|
||||
range.split_off_inclusive(&PartitionKey::new([0xef; 32])).unwrap_err();
|
||||
range.split_off_inclusive(&PartitionKey::new([0xff; 32])).unwrap_err();
|
||||
|
||||
let mut range = PartitionKeyRange::new(PartitionKey::new([0xbf; 32]), PartitionKey::new([0xff; 32])).unwrap();
|
||||
range.split_off_inclusive(&PartitionKey::new([0x00; 32])).unwrap_err();
|
||||
range.split_off_inclusive(&PartitionKey::new([0xbe; 32])).unwrap_err();
|
||||
range.split_off_inclusive(&range.first().checked_sub(1).unwrap()).unwrap_err();
|
||||
|
||||
let mut range = PartitionKeyRange::new(PartitionKey::new([0xff; 32]), PartitionKey::new([0xff; 32])).unwrap();
|
||||
range.split_off_inclusive(&PartitionKey::new([0x00; 32])).unwrap_err();
|
||||
range.split_off_inclusive(&PartitionKey::new([0xfe; 32])).unwrap_err();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checked_add() {
|
||||
for index in 0..32 {
|
||||
for index_value in 0x00..0xfe {
|
||||
let mut value = [0x00; 32];
|
||||
for byte in value[index + 1..32].iter_mut() {
|
||||
*byte = 0xff;
|
||||
}
|
||||
value[index] = index_value;
|
||||
let mut addend = [0x00; 32];
|
||||
addend[index] = index_value + 1;
|
||||
assert_eq!(PartitionKey::new(value).checked_add(1).unwrap(), &addend);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checked_sub() {
|
||||
for index in 0..32 {
|
||||
for index_value in 0x01..0xff {
|
||||
let mut value = [0x00; 32];
|
||||
value[index] = index_value;
|
||||
let mut addend = [0x00; 32];
|
||||
addend[index] = index_value - 1;
|
||||
for byte in addend[index + 1..32].iter_mut() {
|
||||
*byte = 0xff;
|
||||
}
|
||||
assert_eq!(PartitionKey::new(value).checked_sub(1).unwrap(), &addend);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checked_add_overflow() {
|
||||
assert_eq!(PartitionKey::new([0xff; 32]).checked_add(1), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn checked_sub_overflow() {
|
||||
assert_eq!(PartitionKey::new([0x00; 32]).checked_sub(1), None);
|
||||
}
|
||||
}
|
||||
242
enclave/kbupd_enclave/src/service/replica/replica_group.rs
Normal file
242
enclave/kbupd_enclave/src/service/replica/replica_group.rs
Normal file
@ -0,0 +1,242 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
use std::fmt;
|
||||
use std::rc::*;
|
||||
use std::time::*;
|
||||
|
||||
use sgxsd_ffi::{RdRand};
|
||||
|
||||
use crate::protobufs::kbupd_enclave::*;
|
||||
use crate::raft::*;
|
||||
use crate::remote::*;
|
||||
use crate::storage::*;
|
||||
use crate::util::{ListDisplay};
|
||||
|
||||
use super::*;
|
||||
|
||||
const ATTESTATION_EXPIRATION_WINDOW: Duration = Duration::from_secs(86400);
|
||||
|
||||
pub(super) struct ReplicaGroupState {
|
||||
pub raft: RaftState<RaftLogStorage, RdRand, NodeId>,
|
||||
|
||||
remotes: Box<[RemoteReplicaState]>,
|
||||
|
||||
attestation_time_ticks: u32,
|
||||
request_quote_ticks: u32,
|
||||
|
||||
attestation_time_now: Duration,
|
||||
}
|
||||
|
||||
pub(super) struct RemoteReplicaState {
|
||||
pub sender: ReplicaRemoteSender,
|
||||
}
|
||||
|
||||
//
|
||||
// ReplicaGroupState impls
|
||||
//
|
||||
|
||||
impl ReplicaGroupState {
|
||||
pub fn new(raft: RaftState<RaftLogStorage, RdRand, NodeId>,
|
||||
remotes: Box<[RemoteReplicaState]>)
|
||||
-> Self
|
||||
{
|
||||
Self {
|
||||
raft,
|
||||
remotes,
|
||||
attestation_time_ticks: 0,
|
||||
request_quote_ticks: 0,
|
||||
attestation_time_now: Duration::from_secs(0),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn id(&self) -> &RaftGroupId {
|
||||
self.raft.group_id()
|
||||
}
|
||||
|
||||
pub fn set_config(&mut self, config: &EnclaveReplicaConfig) {
|
||||
self.raft.log_mut().set_index_cache_size(config.raft_log_index_page_cache_size.to_usize());
|
||||
self.raft.set_election_timeout_ticks(config.election_timeout_ticks);
|
||||
self.raft.set_heartbeat_timeout_ticks(config.heartbeat_timeout_ticks);
|
||||
self.raft.set_replication_chunk_size(config.replication_chunk_size.to_usize());
|
||||
}
|
||||
|
||||
pub fn get(&self, node_id: &NodeId) -> Option<&RemoteReplicaState> {
|
||||
self.remotes.iter().find(|replica: &&RemoteReplicaState| replica.sender.id() == node_id)
|
||||
}
|
||||
|
||||
pub fn timer_tick(&mut self,
|
||||
max_attestation_time_ticks: u32,
|
||||
max_request_quote_ticks: u32,
|
||||
now: Duration)
|
||||
-> Option<TransactionData> {
|
||||
self.attestation_time_ticks = self.attestation_time_ticks.saturating_add(1);
|
||||
self.request_quote_ticks = self.request_quote_ticks.saturating_add(1);
|
||||
|
||||
if self.request_quote_ticks >= max_request_quote_ticks {
|
||||
self.request_quote_ticks = Default::default();
|
||||
|
||||
for remote in &mut self.remotes[..] {
|
||||
let _ignore = remote.sender.request_quote(EnclaveGetQuoteRequest {});
|
||||
}
|
||||
}
|
||||
|
||||
if self.attestation_time_ticks >= max_attestation_time_ticks {
|
||||
if now > self.attestation_time_now {
|
||||
match self.check_quorum_attestation_time(now) {
|
||||
Ok(()) => {
|
||||
self.attestation_time_ticks = 0;
|
||||
Some(TransactionData {
|
||||
inner: Some(transaction_data::Inner::SetTime(SetTimeTransaction {
|
||||
now_secs: now.as_secs(),
|
||||
})),
|
||||
})
|
||||
}
|
||||
Err(invalid) => {
|
||||
if self.attestation_time_ticks.checked_rem(max_attestation_time_ticks) == Some(0) {
|
||||
info!("not setting attestation time to {} with invalid attestations for {} of {} replicas: {}",
|
||||
now.as_secs(), invalid.len(), self.remotes.iter().len(), ListDisplay(invalid));
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if now < self.attestation_time_now {
|
||||
warn!("not setting attestation time backward from {} to {}",
|
||||
self.attestation_time_now.as_secs(), now.as_secs());
|
||||
}
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_authorized(&self, node_id: &NodeId) -> bool {
|
||||
(self.get(node_id))
|
||||
.map(|replica: &RemoteReplicaState| replica.check_attestation_time(self.attestation_time_now))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
pub fn set_attestation_time_now(&mut self, now: Duration) -> bool {
|
||||
if now > self.attestation_time_now {
|
||||
for replica in self.remotes.iter() {
|
||||
if !replica.check_attestation_time(now) {
|
||||
if let Some(attestation) = replica.attestation() {
|
||||
warn!("replica {} is now invalid at {}: {}",
|
||||
replica.sender.id(), now.as_secs(), attestation);
|
||||
}
|
||||
}
|
||||
}
|
||||
info!("set attestation time from {} to {}",
|
||||
self.attestation_time_now.as_secs(), now.as_secs());
|
||||
self.attestation_time_now = now;
|
||||
true
|
||||
} else {
|
||||
now < self.attestation_time_now
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_attestation_time_now(&self) -> Duration {
|
||||
self.attestation_time_now
|
||||
}
|
||||
|
||||
pub fn attestation(&self) -> AttestationParameters {
|
||||
AttestationParameters::new(self.attestation_time_now)
|
||||
}
|
||||
|
||||
pub fn attestation_expiration_window(&self) -> AttestationParameters {
|
||||
let min_unix_timestamp = self.attestation_time_now.checked_sub(ATTESTATION_EXPIRATION_WINDOW).unwrap_or_default();
|
||||
AttestationParameters::new(min_unix_timestamp)
|
||||
}
|
||||
|
||||
fn check_quorum_attestation_time(&self, now: Duration) -> Result<(), Vec<&RemoteReplicaState>> {
|
||||
let replicas_iter = self.remotes.iter();
|
||||
let replicas_len = replicas_iter.len();
|
||||
let invalid: Vec<_> = replicas_iter
|
||||
.filter(|replica: &&RemoteReplicaState| !replica.check_attestation_time(now))
|
||||
.collect();
|
||||
if invalid.len() < quorum_size(replicas_len) {
|
||||
if invalid.is_empty() {
|
||||
info!("setting attestation time to {}", now.as_secs());
|
||||
} else {
|
||||
warn!("setting attestation time to {} with invalid attestations for {} of {} replicas: {}",
|
||||
now.as_secs(), invalid.len(), replicas_len, ListDisplay(invalid));
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(invalid)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_raft_message(&self, sendable: SendableRaftMessage<NodeId>) {
|
||||
match sendable {
|
||||
SendableRaftMessage::Broadcast { message } => {
|
||||
let r2r_message = Rc::new(ReplicaToReplicaMessage {
|
||||
inner: Some(replica_to_replica_message::Inner::RaftMessage(message)),
|
||||
});
|
||||
for replica in self.remotes.iter() {
|
||||
if replica.check_attestation_time(self.attestation_time_now) {
|
||||
let _ignore = replica.sender.send(Rc::clone(&r2r_message));
|
||||
} else {
|
||||
verbose!("dropping broadcast message to {} with expired attestation {}",
|
||||
replica.sender.id(), OptionDisplay(replica.attestation()));
|
||||
}
|
||||
}
|
||||
}
|
||||
SendableRaftMessage::Reply { message, from } => {
|
||||
if let Some(replica) = self.get(&from) {
|
||||
if replica.check_attestation_time(self.attestation_time_now) {
|
||||
let r2r_message = Rc::new(ReplicaToReplicaMessage {
|
||||
inner: Some(replica_to_replica_message::Inner::RaftMessage(message)),
|
||||
});
|
||||
|
||||
let _ignore = replica.sender.send(r2r_message);
|
||||
} else {
|
||||
warn!("dropping message to {} with expired attestation {}: {}",
|
||||
replica.sender.id(), OptionDisplay(replica.attestation()), message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// RemoteReplicaState impls
|
||||
//
|
||||
|
||||
impl RemoteReplicaState {
|
||||
pub fn attestation(&self) -> Option<AttestationParameters> {
|
||||
self.sender.attestation()
|
||||
}
|
||||
|
||||
fn check_attestation_time(&self, now: Duration) -> bool {
|
||||
let min_unix_timestamp = now.checked_sub(ATTESTATION_EXPIRATION_WINDOW).unwrap_or_default();
|
||||
let min_attestation = AttestationParameters::new(min_unix_timestamp);
|
||||
self.attestation() >= Some(min_attestation)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for RemoteReplicaState {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let Self { sender } = self;
|
||||
write!(fmt, "({}, {})", sender, OptionDisplay(sender.attestation()))
|
||||
}
|
||||
}
|
||||
26
enclave/kbupd_enclave/src/storage/mod.rs
Normal file
26
enclave/kbupd_enclave/src/storage/mod.rs
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
pub mod storage_array;
|
||||
pub mod storage_data;
|
||||
pub mod storage_page_cache;
|
||||
pub mod raft_log;
|
||||
|
||||
pub use self::storage_array::*;
|
||||
pub use self::storage_data::*;
|
||||
pub use self::storage_page_cache::*;
|
||||
pub use self::raft_log::*;
|
||||
131
enclave/kbupd_enclave/src/storage/raft_log/mod.rs
Normal file
131
enclave/kbupd_enclave/src/storage/raft_log/mod.rs
Normal file
@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
mod raft_log_data;
|
||||
mod raft_log_index;
|
||||
|
||||
use sgx_ffi::util::{SecretValue};
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::protobufs::raft::*;
|
||||
use crate::raft::*;
|
||||
use crate::util::*;
|
||||
|
||||
use self::raft_log_data::*;
|
||||
use self::raft_log_index::*;
|
||||
|
||||
pub struct RaftLogStorage {
|
||||
index: RaftLogIndex,
|
||||
data: RaftLogData,
|
||||
cancelled: Vec<SecretValue<Vec<u8>>>,
|
||||
}
|
||||
|
||||
//
|
||||
// RaftLog impls
|
||||
//
|
||||
|
||||
impl RaftLogStorage {
|
||||
pub fn new(data_size: usize, index_size: u32, index_cache_size: usize) -> Result<Self, ()> {
|
||||
Ok(Self {
|
||||
index: RaftLogIndex::new(index_size, index_cache_size)?,
|
||||
data: RaftLogData::new(data_size)?,
|
||||
cancelled: Default::default(),
|
||||
})
|
||||
}
|
||||
pub fn take_cancelled(&mut self) -> Vec<SecretValue<Vec<u8>>> {
|
||||
std::mem::replace(&mut self.cancelled, Default::default())
|
||||
}
|
||||
pub fn data_len(&self) -> usize {
|
||||
self.data.len()
|
||||
}
|
||||
pub fn set_index_cache_size(&mut self, index_cache_size: usize) {
|
||||
self.index.set_cache_size(index_cache_size);
|
||||
}
|
||||
}
|
||||
impl RaftLog for RaftLogStorage {
|
||||
fn append(&mut self, log_entry: LogEntry) -> Result<(), RaftLogAppendError> {
|
||||
let term = log_entry.term;
|
||||
if !self.index.is_full() {
|
||||
let data_entry = if !log_entry.data.is_empty() {
|
||||
let data_entry = self.data.append(log_entry)?;
|
||||
Some(data_entry)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let index_entry = RaftLogIndexEntry { term, data: data_entry };
|
||||
if let Ok(()) = self.index.push_back(index_entry) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(RaftLogAppendError::InternalError)
|
||||
}
|
||||
} else {
|
||||
Err(RaftLogAppendError::OutOfSpace { log_entry })
|
||||
}
|
||||
}
|
||||
fn pop_front(&mut self, truncate_to: LogIdx) -> Result<(), ()> {
|
||||
if (!self.index.is_empty() &&
|
||||
self.index.prev_log_idx() < truncate_to)
|
||||
{
|
||||
if let Some(popped_entry) = self.index.pop_front() {
|
||||
if let Some(popped_data_entry) = &popped_entry.data {
|
||||
self.data.pop_front_to(popped_data_entry);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
fn cancel_from(&mut self, from_log_idx: LogIdx) -> Result<usize, ()> {
|
||||
let cancelled_data_entries = self.index.cancel_from(from_log_idx)?;
|
||||
self.cancelled = self.data.cancel(cancelled_data_entries);
|
||||
Ok(self.cancelled.len())
|
||||
}
|
||||
fn get(&mut self, log_idx: LogIdx) -> Option<LogEntry> {
|
||||
let index_entry = self.index.get(log_idx)?;
|
||||
let entry_data = if let Some(data_entry) = &index_entry.data {
|
||||
self.data.read(data_entry)?
|
||||
} else {
|
||||
SecretValue::new(Vec::new())
|
||||
};
|
||||
Some(LogEntry::new(index_entry.term, entry_data))
|
||||
}
|
||||
fn get_len(&mut self, log_idx: LogIdx) -> Option<usize> {
|
||||
let index_entry = self.index.get(log_idx)?;
|
||||
if let Some(data_entry) = &index_entry.data {
|
||||
Some(data_entry.length.to_usize())
|
||||
} else {
|
||||
Some(0)
|
||||
}
|
||||
}
|
||||
fn get_term(&mut self, log_idx: LogIdx) -> Option<TermId> {
|
||||
if log_idx == self.index.prev_log_idx() {
|
||||
self.index.prev_log_term()
|
||||
} else {
|
||||
self.index.get(log_idx).map(|entry| entry.term)
|
||||
}
|
||||
}
|
||||
fn prev_idx(&self) -> LogIdx {
|
||||
self.index.prev_log_idx()
|
||||
}
|
||||
fn last_idx(&self) -> LogIdx {
|
||||
self.index.last_log_idx()
|
||||
}
|
||||
fn last_term(&self) -> TermId {
|
||||
self.index.last_log_term()
|
||||
}
|
||||
}
|
||||
128
enclave/kbupd_enclave/src/storage/raft_log/raft_log_data.rs
Normal file
128
enclave/kbupd_enclave/src/storage/raft_log/raft_log_data.rs
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Open Whisper Systems
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
use num_traits::{ToPrimitive};
|
||||
use sgx_ffi::util::{SecretValue};
|
||||
|
||||
use crate::protobufs::raft::LogEntry;
|
||||
use crate::raft::*;
|
||||
use crate::storage::storage_data::*;
|
||||
use crate::util::*;
|
||||
|
||||
pub struct RaftLogData {
|
||||
storage: StorageData,
|
||||
|
||||
head: usize,
|
||||
tail: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct RaftLogDataEntry {
|
||||
pub nonce: StorageDataNonce,
|
||||
pub offset: usize,
|
||||
pub length: u32,
|
||||
}
|
||||
|
||||
impl RaftLogData {
|
||||
pub fn new(data_size: usize) -> Result<Self, ()> {
|
||||
Ok(Self {
|
||||
storage: StorageData::new(data_size)?,
|
||||
head: Default::default(),
|
||||
tail: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
if let Some(len) = self.head.checked_sub(self.tail) {
|
||||
len
|
||||
} else {
|
||||
self.storage.len().saturating_sub(self.tail)
|
||||
.saturating_add(self.head)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn append(&mut self, log_entry: LogEntry) -> Result<RaftLogDataEntry, RaftLogAppendError> {
|
||||
let append_len = log_entry.data.len().saturating_add(StorageData::tag_len().into());
|
||||
let append_len = match append_len.to_u32() {
|
||||
Some(append_len) if append_len.to_usize() < self.storage.len() => append_len,
|
||||
Some(_) | None => {
|
||||
error!("transaction too large at {} bytes (have {} bytes of storage)", log_entry.data.len(), self.storage.len());
|
||||
return Err(RaftLogAppendError::TooLarge { size: append_len });
|
||||
}
|
||||
};
|
||||
let mut offset = self.head;
|
||||
let mut new_head = offset.saturating_add(append_len.to_usize());
|
||||
if new_head >= self.storage.len() {
|
||||
if self.tail > 0 {
|
||||
offset = 0;
|
||||
new_head = append_len.to_usize();
|
||||
} else {
|
||||
return Err(RaftLogAppendError::OutOfSpace { log_entry });
|
||||
}
|
||||
}
|
||||
|
||||
if offset < self.tail && new_head >= self.tail {
|
||||
Err(RaftLogAppendError::OutOfSpace { log_entry })
|
||||
} else {
|
||||
self.head = new_head;
|
||||
|
||||
match self.storage.write(offset, log_entry.into_data()) {
|
||||
Ok(nonce) => {
|
||||
Ok(RaftLogDataEntry { nonce, offset, length: append_len })
|
||||
}
|
||||
Err(()) => {
|
||||
error!("wrote out of bounds to raft log at {} len {}", offset, append_len);
|
||||
Err(RaftLogAppendError::InternalError)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn cancel(&mut self, cancelled_data_entries: Vec<RaftLogDataEntry>) -> Vec<SecretValue<Vec<u8>>> {
|
||||
if let Some(cancel_from_data_entry) = cancelled_data_entries.get(0) {
|
||||
self.head = cancel_from_data_entry.offset;
|
||||
}
|
||||
|
||||
let mut cancelled_data = Vec::new();
|
||||
for cancelled_data_entry in cancelled_data_entries {
|
||||
if let Some(data) = self.read(&cancelled_data_entry) {
|
||||
cancelled_data.push(data);
|
||||
}
|
||||
}
|
||||
cancelled_data
|
||||
}
|
||||
|
||||
pub fn pop_front_to(&mut self, popped_entry: &RaftLogDataEntry) {
|
||||
let tail = popped_entry.offset.saturating_add(popped_entry.length.to_usize());
|
||||
if tail < self.storage.len() {
|
||||
self.tail = tail;
|
||||
} else {
|
||||
self.tail = Default::default();
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(&self, data_entry: &RaftLogDataEntry) -> Option<SecretValue<Vec<u8>>> {
|
||||
if let Ok(data) = self.storage.read(data_entry.offset, data_entry.length.to_usize(), data_entry.nonce) {
|
||||
Some(data)
|
||||
} else {
|
||||
error!("error reading raft log entry at offset {} length {}", data_entry.offset, data_entry.length);
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user