mirror of
https://github.com/deneraraujo/OpenVPNAdapter.git
synced 2026-04-24 00:00:05 +08:00
Merge commit 'f65d76170b26155358c2fc27686f87e0475f6a94' as 'OpenVPN Adapter/Vendors/openvpn'
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
README.html
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
Contributor agreement for the OpenVPN project version 1.2 - March 2017
|
||||||
|
########################################################################
|
||||||
|
|
||||||
|
This Contributor Agreement consists of two parts. Part I is the
|
||||||
|
Developer Certificate of Origin available at
|
||||||
|
http://developercertificate.org/.
|
||||||
|
|
||||||
|
In this contributor agreement, "This project" refers to the OpenVPN
|
||||||
|
project and
|
||||||
|
"open source license indicated in `the file <LICENSE.rst>`_" refers to
|
||||||
|
the GPLv3 license with an additional permission that allows linking
|
||||||
|
the OpenSSL software, https://www.openssl.org/, with the OpenVPN
|
||||||
|
software.
|
||||||
|
|
||||||
|
Part I
|
||||||
|
######
|
||||||
|
|
||||||
|
Developer Certificate of Origin Version 1.1
|
||||||
|
|
||||||
|
Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 1
|
||||||
|
Letterman Drive Suite D4700 San Francisco, CA, 94129
|
||||||
|
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies of this
|
||||||
|
license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Developer's Certificate of Origin 1.1
|
||||||
|
|
||||||
|
By making a contribution to this project, I certify that:
|
||||||
|
|
||||||
|
(a) The contribution was created in whole or in part by me and I have
|
||||||
|
the right to submit it under the open source license indicated in the
|
||||||
|
file; or
|
||||||
|
|
||||||
|
(b) The contribution is based upon previous work that, to the best of
|
||||||
|
my knowledge, is covered under an appropriate open source license and
|
||||||
|
I have the right under that license to submit that work with
|
||||||
|
modifications, whether created in whole or in part by me, under the
|
||||||
|
same open source license (unless I am permitted to submit under a
|
||||||
|
different license), as indicated in the file; or
|
||||||
|
|
||||||
|
(c) The contribution was provided directly to me by some other person
|
||||||
|
who certified (a), (b) or (c) and I have not modified it.
|
||||||
|
|
||||||
|
(d) I understand and agree that this project and the contribution are
|
||||||
|
public and that a record of the contribution (including all personal
|
||||||
|
information I submit with it, including my sign-off) is maintained
|
||||||
|
indefinitely and may be redistributed consistent with this project or
|
||||||
|
the open source license(s) involved.
|
||||||
|
|
||||||
|
Part II
|
||||||
|
#######
|
||||||
|
|
||||||
|
Copyright (C) 2017 OpenVPN Technologies, Inc.
|
||||||
|
|
||||||
|
In addition:
|
||||||
|
|
||||||
|
(e) I understand that OpenVPN Technologies, Inc. may relicense this
|
||||||
|
project, this contribution, and any modification to it under any
|
||||||
|
license. I certify that I, or the person on whose behalf I am
|
||||||
|
submitting the contribution, have the right to grant and hereby grant
|
||||||
|
OpenVPN Technologies, Inc. a license to do so for this
|
||||||
|
contribution. My grant is made on the condition that OpenVPN
|
||||||
|
Technologies, Inc. will make any modification to this contribution
|
||||||
|
available to the OpenVPN project under the open source license
|
||||||
|
indicated in the file.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
Contributing to OpenVPN 3
|
||||||
|
=========================
|
||||||
|
|
||||||
|
Patches can be sent as GitHub pull requests.
|
||||||
|
|
||||||
|
Note that by contributing to the OpenVPN 3 project you accept the Contributor
|
||||||
|
License Agreement described in `CLA.rst <CLA.rst>`_.
|
||||||
@@ -0,0 +1,674 @@
|
|||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 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 General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
the GNU General Public License is 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. We, the Free Software Foundation, use the
|
||||||
|
GNU General Public License for most of our software; it applies also to
|
||||||
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
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 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. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
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 Affero 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 special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU 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 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 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 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 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 General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU 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 the program does terminal interaction, make it output a short
|
||||||
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
|
<program> Copyright (C) <year> <name of author>
|
||||||
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, your program's commands
|
||||||
|
might be different; for a GUI interface, you would use an "about box".
|
||||||
|
|
||||||
|
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 GPL, see
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
The GNU General Public License does not permit incorporating your program
|
||||||
|
into proprietary programs. If your program is a subroutine library, you
|
||||||
|
may consider it more useful to permit linking proprietary applications with
|
||||||
|
the library. If this is what you want to do, use the GNU Lesser General
|
||||||
|
Public License instead of this License. But first, please read
|
||||||
|
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
OpenVPN 3 is distributed under
|
||||||
|
`GNU General Public License version 3 <COPYRIGHT.GPLV3>`_
|
||||||
|
with a special permission to link against OpenSSL:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
Additional permission under GNU GPL version 3 section 7
|
||||||
|
|
||||||
|
If you modify this Program, or any covered work, by linking or combining
|
||||||
|
it with OpenSSL (or a modified version of that library), containing parts
|
||||||
|
covered by the terms of the OpenSSL License or the Original SSLeay License,
|
||||||
|
the licensors of this Program grant you additional permission to convey the
|
||||||
|
resulting work. Corresponding Source for a non-source form of such a
|
||||||
|
combination shall include the source code for the parts of OpenSSL used as
|
||||||
|
well as that of the covered work.
|
||||||
@@ -0,0 +1,555 @@
|
|||||||
|
OpenVPN 3
|
||||||
|
=========
|
||||||
|
|
||||||
|
OpenVPN 3 is a C++ class library that implements the functionality
|
||||||
|
of an OpenVPN client, and is protocol-compatible with the OpenVPN
|
||||||
|
2.x branch.
|
||||||
|
|
||||||
|
OpenVPN 3 includes a minimal client wrapper (``cli``) that links in with
|
||||||
|
the library and provides basic command line functionality.
|
||||||
|
|
||||||
|
OpenVPN 3 is currently used in production as the core of the
|
||||||
|
OpenVPN Connect clients for iOS, Android, Linux, Windows, and Mac OS X.
|
||||||
|
|
||||||
|
NOTE: As of 2017, OpenVPN 3 is primarily of interest to developers,
|
||||||
|
as it does not yet replicate the full functionality of OpenVPN 2.x.
|
||||||
|
In particular, server functionality is not yet implemented.
|
||||||
|
|
||||||
|
.. contents:: Table of Contents
|
||||||
|
|
||||||
|
OpenVPN 3 Client API
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
OpenVPN 3 is organized as a C++ class library, and the API is defined in
|
||||||
|
`<client/ovpncli.hpp>`_.
|
||||||
|
|
||||||
|
A simple command-line wrapper for the API is provided in
|
||||||
|
`<test/ovpncli/cli.cpp>`_.
|
||||||
|
|
||||||
|
Building the OpenVPN 3 client on Linux
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
These instructions were tested on Ubuntu 16.
|
||||||
|
|
||||||
|
Get prerequisites to allow for either mbedTLS or OpenSSL linkage::
|
||||||
|
|
||||||
|
$ sudo apt-get install g++ make libmbedtls-dev libssl-dev liblz4-dev
|
||||||
|
|
||||||
|
Get Asio C++ library::
|
||||||
|
|
||||||
|
$ cd ~
|
||||||
|
$ git clone https://github.com/chriskohlhoff/asio.git
|
||||||
|
|
||||||
|
Set environmental variable used by OpenVPN 3 build scripts::
|
||||||
|
|
||||||
|
$ export O3=~/ovpn3
|
||||||
|
|
||||||
|
Clone the OpenVPN 3 source repo::
|
||||||
|
|
||||||
|
$ mkdir ~/ovpn3
|
||||||
|
$ cd ~/ovpn3
|
||||||
|
$ git clone https://github.com/OpenVPN/openvpn3.git core
|
||||||
|
|
||||||
|
Build the OpenVPN 3 client wrapper (cli) with mbedTLS crypto/ssl library
|
||||||
|
and LZ4 compression::
|
||||||
|
|
||||||
|
$ cd $O3/core/test/ovpncli
|
||||||
|
$ ECHO=1 PROF=linux ASIO_DIR=~/asio MTLS_SYS=1 LZ4_SYS=1 NOSSL=1 $O3/core/scripts/build cli
|
||||||
|
|
||||||
|
Or alternatively build with OpenSSL::
|
||||||
|
|
||||||
|
$ cd $O3/core/test/ovpncli
|
||||||
|
$ ECHO=1 PROF=linux ASIO_DIR=~/asio OPENSSL_SYS=1 LZ4_SYS=1 $O3/core/scripts/build cli
|
||||||
|
|
||||||
|
Run OpenVPN 3 client::
|
||||||
|
|
||||||
|
$ sudo ./cli -a -c yes myprofile.ovpn route-nopull
|
||||||
|
|
||||||
|
Options used::
|
||||||
|
|
||||||
|
-a : use autologin sessions, if supported
|
||||||
|
-c yes : negotiate LZ4 compression
|
||||||
|
myprofile.ovpn : OpenVPN config file (must have .ovpn extension)
|
||||||
|
route-nopull : if you are connected via ssh, prevent ssh session lockout
|
||||||
|
|
||||||
|
|
||||||
|
Building the OpenVPN 3 client on Mac OS X
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
OpenVPN 3 should be built in a non-root Mac OS X account.
|
||||||
|
Make sure that Xcode is installed with optional command-line tools.
|
||||||
|
(These instructions have been tested with Xcode 5.1.1).
|
||||||
|
|
||||||
|
Create the directories ``~/src`` and ``~/src/mac``::
|
||||||
|
|
||||||
|
$ mkdir -p ~/src/mac
|
||||||
|
|
||||||
|
Clone the OpenVPN 3 repo::
|
||||||
|
|
||||||
|
$ cd ~/src
|
||||||
|
$ mkdir ovpn3
|
||||||
|
$ cd ovpn3
|
||||||
|
$ git clone https://github.com/OpenVPN/openvpn3.git core
|
||||||
|
|
||||||
|
Export the shell variable ``O3`` to point to the OpenVPN 3 top level
|
||||||
|
directory::
|
||||||
|
|
||||||
|
export O3=~/src/ovpn3
|
||||||
|
|
||||||
|
Download source tarballs (``.tar.gz`` or ``.tgz``) for these dependency
|
||||||
|
libraries into ``~/Downloads``
|
||||||
|
|
||||||
|
See the file ``$O3/core/deps/lib-versions`` for the expected
|
||||||
|
version numbers of each dependency. If you want to use a different
|
||||||
|
version of the library than listed here, you can edit this file.
|
||||||
|
|
||||||
|
1. Asio — https://github.com/chriskohlhoff/asio
|
||||||
|
2. mbed TLS (2.3.0 or higher) — https://tls.mbed.org/
|
||||||
|
3. LZ4 — https://github.com/Cyan4973/lz4
|
||||||
|
|
||||||
|
For dependencies that are typically cloned from github vs.
|
||||||
|
provided as a .tar.gz file, tools are provided to convert
|
||||||
|
the github to a .tar.gz file. See "snapshot" scripts under
|
||||||
|
``$O3/core/deps``
|
||||||
|
|
||||||
|
Note that while OpenSSL is listed in lib-versions, it is
|
||||||
|
not required for Mac builds.
|
||||||
|
|
||||||
|
Build the dependencies::
|
||||||
|
|
||||||
|
$ OSX_ONLY=1 $O3/core/scripts/mac/build-all
|
||||||
|
|
||||||
|
Now build the OpenVPN 3 client executable::
|
||||||
|
|
||||||
|
$ cd $O3/core
|
||||||
|
$ . vars/vars-osx64
|
||||||
|
$ . vars/setpath
|
||||||
|
$ cd test/ovpncli
|
||||||
|
$ MTLS=1 LZ4=1 build cli
|
||||||
|
|
||||||
|
This will build the OpenVPN 3 client library with a small client
|
||||||
|
wrapper (``cli``). It will also statically link in all external
|
||||||
|
dependencies (Asio, mbedTLS, and LZ4), so ``cli`` may be distributed
|
||||||
|
to other Macs and will run as a standalone executable.
|
||||||
|
|
||||||
|
These build scripts will create a **x86_x64** Mac OS X executable,
|
||||||
|
with a minimum deployment target of 10.8.x. The Mac OS X tuntap driver is not
|
||||||
|
required, as OpenVPN 3 can use the integrated utun interface if
|
||||||
|
available.
|
||||||
|
|
||||||
|
To view the client wrapper options::
|
||||||
|
|
||||||
|
$ ./cli -h
|
||||||
|
|
||||||
|
To connect::
|
||||||
|
|
||||||
|
$ ./cli client.ovpn
|
||||||
|
|
||||||
|
Testing
|
||||||
|
-------
|
||||||
|
|
||||||
|
The OpenVPN 3 core includes a stress/performance test of
|
||||||
|
the OpenVPN protocol implementation. The test basically
|
||||||
|
creates a virtualized lossy network between two OpenVPN
|
||||||
|
protocol objects, triggers TLS negotiations between them,
|
||||||
|
passes control/data channel messages, and measures the ability
|
||||||
|
of the OpenVPN protocol objects to perform and remain in
|
||||||
|
a valid state.
|
||||||
|
|
||||||
|
The OpenVPN protocol implementation that is being tested
|
||||||
|
is here: `<openvpn/ssl/proto.hpp>`_
|
||||||
|
|
||||||
|
The test code itself is here: `<test/ssl/proto.cpp>`_
|
||||||
|
|
||||||
|
Build the test::
|
||||||
|
|
||||||
|
$ cd ovpn3/core/test/ssl
|
||||||
|
$ ECHO=1 PROF=linux ASIO_DIR=~/asio MTLS_SYS=1 NOSSL=1 $O3/core/scripts/build proto
|
||||||
|
|
||||||
|
Run the test::
|
||||||
|
|
||||||
|
$ time ./proto
|
||||||
|
*** app bytes=72777936 net_bytes=122972447 data_bytes=415892854 prog=0000216599/0000216598 D=12700/600/12700/600 N=109/109 SH=17400/15300 HE=0/0
|
||||||
|
|
||||||
|
real 0m15.813s
|
||||||
|
user 0m15.800s
|
||||||
|
sys 0m0.004s
|
||||||
|
|
||||||
|
|
||||||
|
Developer Guide
|
||||||
|
---------------
|
||||||
|
|
||||||
|
OpenVPN 3 is written in C++11 and developers who are moving
|
||||||
|
from C to C++ should take some time to familiarize themselves with
|
||||||
|
key C++ design patterns such as *RAII*:
|
||||||
|
|
||||||
|
https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization
|
||||||
|
|
||||||
|
OpenVPN 3 Client Core
|
||||||
|
+++++++++++++++++++++
|
||||||
|
|
||||||
|
OpenVPN 3 is designed as a class library, with an API that
|
||||||
|
is essentially defined inside of namespace ``ClientAPI``
|
||||||
|
with headers and implementation in `<client>`_ and
|
||||||
|
header-only library files under `<openvpn>`_.
|
||||||
|
|
||||||
|
The consise definition of the client API is essentially ``class OpenVPNClient``
|
||||||
|
in `<client/ovpncli.hpp>`_ with several imporant extensions to
|
||||||
|
the API found in:
|
||||||
|
|
||||||
|
* **class TunBuilderBase** in `<openvpn/tun/builder/base.hpp>`_ —
|
||||||
|
Provides an abstraction layer defining the *tun* interface,
|
||||||
|
and is especially useful for interfacing with an OS-layer VPN API.
|
||||||
|
|
||||||
|
* **class ExternalPKIBase** in `<openvpn/pki/epkibase.hpp>`_ —
|
||||||
|
Provides a callback for external private key operations, and
|
||||||
|
is useful for interfacing with an OS-layer Keychain such as
|
||||||
|
the Keychain on iOS, Mac OS X, and Android, and the Crypto API
|
||||||
|
on Windows.
|
||||||
|
|
||||||
|
* **class LogReceiver** in `<client/ovpncli.hpp>`_ —
|
||||||
|
Provides an abstraction layer for the delivery of logging messages.
|
||||||
|
|
||||||
|
OpenVPN 3 includes a command-line reference client (``cli``) for
|
||||||
|
testing the API. See `<test/ovpncli/cli.cpp>`_.
|
||||||
|
|
||||||
|
The basic approach to building an OpenVPN 3 client is
|
||||||
|
to define a client class that derives from
|
||||||
|
``ClientAPI::OpenVPNClient``, then provide implementations
|
||||||
|
for callbacks including event and logging notifications:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
class Client : public ClientAPI::OpenVPNClient
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual void event(const Event&) override { // events delivered here
|
||||||
|
...
|
||||||
|
}
|
||||||
|
virtual void log(const LogInfo&) override { // logging delivered here
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
...
|
||||||
|
};
|
||||||
|
|
||||||
|
To start the client, first create a ``ClientAPI::Config`` object
|
||||||
|
and initialize it with the OpenVPN config file and other options:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
ClientAPI::Config config;
|
||||||
|
config.content = <config_file_content_as_multiline_string>;
|
||||||
|
...
|
||||||
|
|
||||||
|
Next, create a client object and evaluate the configuration:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
Client client;
|
||||||
|
ClientAPI::EvalConfig eval = client.eval_config(config);
|
||||||
|
if (eval.error)
|
||||||
|
throw ...;
|
||||||
|
|
||||||
|
Finally, in a new worker thread, start the connection:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
ClientAPI::Status connect_status = client.connect();
|
||||||
|
|
||||||
|
Note that ``client.connect()`` will not return until
|
||||||
|
the session has terminated.
|
||||||
|
|
||||||
|
Top Layer
|
||||||
|
.........
|
||||||
|
|
||||||
|
The top layer of the OpenVPN 3 client is implemented
|
||||||
|
in `<test/ovpncli/cli.cpp>`_ and `<openvpn/client/cliopt.hpp>`_.
|
||||||
|
Most of what this code does is marshalling the configuration and
|
||||||
|
dispatching the higher-level objects that implement the OpenVPN
|
||||||
|
client session.
|
||||||
|
|
||||||
|
Connection
|
||||||
|
..........
|
||||||
|
|
||||||
|
``class ClientConnect`` in `<openvpn/client/cliconnect.hpp>`_
|
||||||
|
implements the top-level connection logic for an OpenVPN client
|
||||||
|
connection. It is concerned with starting, stopping, pausing, and resuming
|
||||||
|
OpenVPN client connections. It deals with retrying a connection and handles
|
||||||
|
the connection timeout. It also deals with connection exceptions and understands
|
||||||
|
the difference between an exception that should halt any further reconnection
|
||||||
|
attempts (such as ``AUTH_FAILED``), and other exceptions such as network errors
|
||||||
|
that would justify a retry.
|
||||||
|
|
||||||
|
Some of the methods in the class
|
||||||
|
(such as ``stop``, ``pause``, and ``reconnect``) are often
|
||||||
|
called by another thread that is controlling the connection, therefore
|
||||||
|
thread-safe methods are provided where the thread-safe function posts a message
|
||||||
|
to the actual connection thread.
|
||||||
|
|
||||||
|
In an OpenVPN client connection, the following object stack would be used:
|
||||||
|
|
||||||
|
1. **class ClientConnect** in `<openvpn/client/cliconnect.hpp>`_ —
|
||||||
|
The top-layer object in an OpenVPN client connection.
|
||||||
|
2. **class ClientProto::Session** in `<openvpn/client/cliproto.hpp>`_ —
|
||||||
|
The OpenVPN client protocol object that subinstantiates the transport
|
||||||
|
and tun layer objects.
|
||||||
|
3. **class ProtoContext** in `<openvpn/ssl/proto.hpp>`_ —
|
||||||
|
The core OpenVPN protocol implementation that is common to both
|
||||||
|
client and server.
|
||||||
|
4. **class ProtoStackBase<Packet>** in `<openvpn/ssl/protostack.hpp>`_ —
|
||||||
|
The bottom-layer class that implements
|
||||||
|
the basic functionality of tunneling a protocol over a reliable or
|
||||||
|
unreliable transport layer, but isn't specific to OpenVPN per-se.
|
||||||
|
|
||||||
|
Transport Layer
|
||||||
|
...............
|
||||||
|
|
||||||
|
OpenVPN 3 defines abstract base classes for Transport layer
|
||||||
|
implementations in `<openvpn/transport/client/transbase.hpp>`_.
|
||||||
|
|
||||||
|
Currently, transport layer implementations are provided for:
|
||||||
|
|
||||||
|
* **UDP** — `<openvpn/transport/client/udpcli.hpp>`_
|
||||||
|
* **TCP** — `<openvpn/transport/client/tcpcli.hpp>`_
|
||||||
|
* **HTTP Proxy** — `<openvpn/transport/client/httpcli.hpp>`_
|
||||||
|
|
||||||
|
Tun Layer
|
||||||
|
.........
|
||||||
|
|
||||||
|
OpenVPN 3 defines abstract base classes for Tun layer
|
||||||
|
implementations in `<openvpn/tun/client/tunbase.hpp>`_.
|
||||||
|
|
||||||
|
There are two possible approaches to define a Tun
|
||||||
|
layer implementation:
|
||||||
|
|
||||||
|
1. Use a VPN API-centric model (such as for Android
|
||||||
|
or iOS). These models derive from **class TunBuilderBase**
|
||||||
|
in `<openvpn/tun/builder/base.hpp>`_
|
||||||
|
|
||||||
|
2. Use an OS-specific model such as:
|
||||||
|
|
||||||
|
* **Linux** — `<openvpn/tun/linux/client/tuncli.hpp>`_
|
||||||
|
* **Windows** — `<openvpn/tun/win/client/tuncli.hpp>`_
|
||||||
|
* **Mac OS X** — `<openvpn/tun/mac/client/tuncli.hpp>`_
|
||||||
|
|
||||||
|
Protocol Layer
|
||||||
|
..............
|
||||||
|
|
||||||
|
The OpenVPN protocol is implemented in **class ProtoContext**
|
||||||
|
in `<openvpn/ssl/proto.hpp>`_.
|
||||||
|
|
||||||
|
Options Processing
|
||||||
|
..................
|
||||||
|
|
||||||
|
The parsing and query of the OpenVPN config file
|
||||||
|
is implemented by ``class OptionList`` in
|
||||||
|
`<openvpn/common/options.hpp>`_.
|
||||||
|
|
||||||
|
Note that OpenVPN 3 always assumes an *inline* style of
|
||||||
|
configuration, where all certs, keys, etc. are
|
||||||
|
defined inline rather than through an external file
|
||||||
|
reference.
|
||||||
|
|
||||||
|
For config files that do use external file references,
|
||||||
|
``class ProfileMerge`` in `<openvpn/options/merge.hpp>`_
|
||||||
|
is provided to merge those external
|
||||||
|
file references into an inline form.
|
||||||
|
|
||||||
|
Calling the Client API from other languages
|
||||||
|
...........................................
|
||||||
|
|
||||||
|
The OpenVPN 3 client API, as defined by ``class OpenVPNClient``
|
||||||
|
in `<client/ovpncli.hpp>`_, can be wrapped by the
|
||||||
|
Swig_ tool to create bindings for other languages.
|
||||||
|
|
||||||
|
.. _Swig: http://www.swig.org/
|
||||||
|
|
||||||
|
For example, OpenVPN Connect for Android creates a Java
|
||||||
|
binding of the API using `<javacli/ovpncli.i>`_.
|
||||||
|
|
||||||
|
Security
|
||||||
|
++++++++
|
||||||
|
|
||||||
|
When developing security software in C++, it's very important to
|
||||||
|
take advantage of the language and OpenVPN library code
|
||||||
|
to insulate code from the kinds of
|
||||||
|
bugs that can introduce security vulnerabilities.
|
||||||
|
|
||||||
|
Here is a brief set of guidelines:
|
||||||
|
|
||||||
|
* When dealing with strings, use a ``std::string``
|
||||||
|
rather than a ``char *``.
|
||||||
|
|
||||||
|
* When dealing with binary data or buffers, always try to use a ``Buffer``,
|
||||||
|
``ConstBuffer``, ``BufferAllocated``, or ``BufferPtr`` object to
|
||||||
|
provide managed access to the buffer, to protect against security
|
||||||
|
bugs that arise when using raw buffer pointers.
|
||||||
|
See `<openvpn/buffer/buffer.hpp>`_ for the OpenVPN ``Buffer`` classes.
|
||||||
|
|
||||||
|
* When it's necessary to have a pointer to an object, use
|
||||||
|
``std::unique_ptr<>`` for non-shared objects and reference-counted
|
||||||
|
smart pointers for shared objects. For shared-pointers,
|
||||||
|
OpenVPN code should use the smart pointer classes defined
|
||||||
|
in `<openvpn/common/rc.hpp>`_. Please see the comments in
|
||||||
|
this file for documentation.
|
||||||
|
|
||||||
|
* Never use ``malloc`` or ``free``. When allocating objects,
|
||||||
|
use the C++ ``new`` operator and then immediately construct
|
||||||
|
a smart pointer to reference the object:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
std::unique_ptr<MyObject> ptr = new MyObject();
|
||||||
|
ptr->method();
|
||||||
|
|
||||||
|
* When interfacing with C functions that deal with
|
||||||
|
raw pointers, memory allocation, etc., consider wrapping
|
||||||
|
the functionality in C++. For an example, see ``enum_dir()``
|
||||||
|
in `<openvpn/common/enumdir.hpp>`_,
|
||||||
|
a function that returns a list of files in
|
||||||
|
a directory (Unix only) via a high-level
|
||||||
|
string vector, while internally calling
|
||||||
|
the low level libc methods
|
||||||
|
``opendir``, ``readdir``, and ``closedir``.
|
||||||
|
Notice how ``unique_ptr_del`` is used to wrap the
|
||||||
|
``DIR`` struct in a smart pointer with a custom
|
||||||
|
deletion function.
|
||||||
|
|
||||||
|
* When grabbing random entropy that is to be used
|
||||||
|
for cryptographic purposes (i.e. for keys, tokens, etc.),
|
||||||
|
always ensure that the RNG is crypto-grade by calling
|
||||||
|
``assert_crypto()`` on the RNG. This will throw
|
||||||
|
an exception if the RNG is not crypto-grade:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
void set_rng(RandomAPI::Ptr rng_arg) {
|
||||||
|
rng_arg->assert_crypto();
|
||||||
|
rng = std::move(rng_arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
* Any variable whose value is not expected to change should
|
||||||
|
be declared ``const``.
|
||||||
|
|
||||||
|
* Don't use non-const global or static variables unless absolutely
|
||||||
|
necessary.
|
||||||
|
|
||||||
|
* When formatting strings, don't use ``snprintf``. Instead, use
|
||||||
|
``std::ostringstream`` or build the string using the '+' ``std::string``
|
||||||
|
operator:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
std::string format_reconnecting(const int n_seconds) {
|
||||||
|
return "Reconnecting in " + openvpn::to_string(n_seconds) + " seconds.";
|
||||||
|
}
|
||||||
|
|
||||||
|
or:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
std::string format_reconnecting(const int n_seconds) {
|
||||||
|
std::ostringstream os;
|
||||||
|
os << "Reconnecting in " << n_seconds << " seconds.";
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
* OpenVPN 3 is a "header-only" library, therefore all free functions
|
||||||
|
outside of classes should have the ``inline`` attribute.
|
||||||
|
|
||||||
|
Conventions
|
||||||
|
+++++++++++
|
||||||
|
|
||||||
|
* Use the **Asio** library for I/O and timers.
|
||||||
|
Don't deal with sockets directly.
|
||||||
|
|
||||||
|
* Never block. If you need to wait for something, use **Asio** timers
|
||||||
|
or sockets.
|
||||||
|
|
||||||
|
* Use the ``OPENVPN_LOG()`` macro to log stuff. Don't use ``printf``.
|
||||||
|
|
||||||
|
* Don't call crypto/ssl libraries directly. Instead use the abstraction
|
||||||
|
layers (`<openvpn/crypto>`_ and `<openvpn/ssl>`_) that allow OpenVPN
|
||||||
|
to link with different crypto/ssl libraries (such as **OpenSSL**
|
||||||
|
or **mbed TLS**).
|
||||||
|
|
||||||
|
* Use ``RandomAPI`` as a wrapper for random number
|
||||||
|
generators (`<openvpn/random/randapi.hpp>`_).
|
||||||
|
|
||||||
|
* If you need to deal with configuration file options,
|
||||||
|
see ``class OptionList`` in `<openvpn/common/options.hpp>`_.
|
||||||
|
|
||||||
|
* If you need to deal with time or time durations, use the
|
||||||
|
classes under `<openvpn/time>`_.
|
||||||
|
|
||||||
|
* If you need to deal with IP addresses, see the comprehensive classes
|
||||||
|
under `<openvpn/addr>`_.
|
||||||
|
|
||||||
|
* In general, if you need a general-purpose library class or function,
|
||||||
|
look under `<openvpn/common>`_. Chances are good that it's already
|
||||||
|
been implemented.
|
||||||
|
|
||||||
|
* The OpenVPN 3 approach to errors is to count them, rather than
|
||||||
|
unconditionally log them. If you need to add a new error
|
||||||
|
counter, see `<openvpn/error/error.hpp>`_.
|
||||||
|
|
||||||
|
* If you need to create a new event type which can be transmitted
|
||||||
|
as a notification back to the client API user, see
|
||||||
|
`<openvpn/client/clievent.hpp>`_.
|
||||||
|
|
||||||
|
* Raw pointers or references can be okay when used by an object to
|
||||||
|
point back to its parent (or container), if you can guarantee that
|
||||||
|
the object will not outlive its parent. Backreferences to a parent
|
||||||
|
object is also a common use case for weak pointers.
|
||||||
|
|
||||||
|
* Use C++ exceptions for error handling and as an alternative
|
||||||
|
to ``goto``. See OpenVPN's general exception classes
|
||||||
|
and macros in `<openvpn/common/exception.hpp>`_.
|
||||||
|
|
||||||
|
* Use C++ destructors for automatic object cleanup, and so
|
||||||
|
that thrown exceptions will not leak objects. Alternatively,
|
||||||
|
use ``Cleanup`` in `<openvpn/common/cleanup.hpp>`_ when
|
||||||
|
you need to specify a code block to execute prior to scope
|
||||||
|
exit. For example, ensure that the file ``pid_fn`` is
|
||||||
|
deleted before scope exit:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
auto clean = Cleanup([pid_fn]() {
|
||||||
|
if (pid_fn)
|
||||||
|
::unlink(pid_fn);
|
||||||
|
});
|
||||||
|
|
||||||
|
* When calling global methods (such as libc ``fork``),
|
||||||
|
prepend "::" to the symbol name, e.g.:
|
||||||
|
|
||||||
|
.. code:: c++
|
||||||
|
|
||||||
|
struct dirent *e;
|
||||||
|
while ((e = ::readdir(dir.get())) != nullptr) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
* Use ``nullptr`` instead of ``NULL``.
|
||||||
|
|
||||||
|
Threading
|
||||||
|
+++++++++
|
||||||
|
|
||||||
|
The OpenVPN 3 client core is designed to run in a single thread, with
|
||||||
|
the UI or controller driving the OpenVPN API running in a different
|
||||||
|
thread.
|
||||||
|
|
||||||
|
It's almost never necessary to create additional threads within
|
||||||
|
the OpenVPN 3 client core.
|
||||||
|
|
||||||
|
|
||||||
|
Contributing
|
||||||
|
------------
|
||||||
|
|
||||||
|
See `<CONTRIBUTING.rst>`_.
|
||||||
|
|
||||||
|
License
|
||||||
|
-------
|
||||||
|
|
||||||
|
See `<LICENSE.rst>`_.
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,573 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// API for OpenVPN Client, may be used standalone or wrapped by swig.
|
||||||
|
// Use ovpncli.i to wrap the API for swig.
|
||||||
|
// The crux of the API is defined in OpenVPNClient (below)
|
||||||
|
// and TunBuilderBase.
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <openvpn/tun/builder/base.hpp>
|
||||||
|
#include <openvpn/pki/epkibase.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
class OptionList;
|
||||||
|
class ProfileMerge;
|
||||||
|
class Stop;
|
||||||
|
|
||||||
|
namespace ClientAPI {
|
||||||
|
// Represents an OpenVPN server and its friendly name
|
||||||
|
// (client reads)
|
||||||
|
struct ServerEntry
|
||||||
|
{
|
||||||
|
std::string server;
|
||||||
|
std::string friendlyName;
|
||||||
|
};
|
||||||
|
|
||||||
|
// return properties of config
|
||||||
|
// (client reads)
|
||||||
|
struct EvalConfig
|
||||||
|
{
|
||||||
|
// true if error
|
||||||
|
bool error = false;
|
||||||
|
|
||||||
|
// if error, message given here
|
||||||
|
std::string message;
|
||||||
|
|
||||||
|
// this username must be used with profile
|
||||||
|
std::string userlockedUsername;
|
||||||
|
|
||||||
|
// profile name of config
|
||||||
|
std::string profileName;
|
||||||
|
|
||||||
|
// "friendly" name of config
|
||||||
|
std::string friendlyName;
|
||||||
|
|
||||||
|
// true: no creds required, false: username/password required
|
||||||
|
bool autologin = false;
|
||||||
|
|
||||||
|
// if true, this is an External PKI profile (no cert or key directives)
|
||||||
|
bool externalPki = false;
|
||||||
|
|
||||||
|
// static challenge, may be empty, ignored if autologin
|
||||||
|
std::string staticChallenge;
|
||||||
|
|
||||||
|
// true if static challenge response should be echoed to UI, ignored if autologin
|
||||||
|
bool staticChallengeEcho = false;
|
||||||
|
|
||||||
|
// true if this profile requires a private key password
|
||||||
|
bool privateKeyPasswordRequired = false;
|
||||||
|
|
||||||
|
// true if user is allowed to save authentication password in UI
|
||||||
|
bool allowPasswordSave = false;
|
||||||
|
|
||||||
|
// information about the first remote item in config
|
||||||
|
std::string remoteHost; // will be overridden by Config::serverOverride if defined
|
||||||
|
std::string remotePort;
|
||||||
|
std::string remoteProto;
|
||||||
|
|
||||||
|
// optional list of user-selectable VPN servers
|
||||||
|
std::vector<ServerEntry> serverList;
|
||||||
|
};
|
||||||
|
|
||||||
|
// used to pass credentials to VPN core
|
||||||
|
// (client writes)
|
||||||
|
struct ProvideCreds
|
||||||
|
{
|
||||||
|
std::string username;
|
||||||
|
std::string password;
|
||||||
|
|
||||||
|
// response to challenge
|
||||||
|
std::string response;
|
||||||
|
|
||||||
|
// Dynamic challenge/response cookie
|
||||||
|
std::string dynamicChallengeCookie;
|
||||||
|
|
||||||
|
// If true, on successful connect, we will replace the password
|
||||||
|
// with the session ID we receive from the server (if provided).
|
||||||
|
// If false, the password will be cached for future reconnects
|
||||||
|
// and will not be replaced with a session ID, even if the
|
||||||
|
// server provides one.
|
||||||
|
bool replacePasswordWithSessionID = false;
|
||||||
|
|
||||||
|
// If true, and if replacePasswordWithSessionID is true, and if
|
||||||
|
// we actually receive a session ID from the server, cache
|
||||||
|
// the user-provided password for future use before replacing
|
||||||
|
// the active password with the session ID.
|
||||||
|
bool cachePassword = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// used to get session token from VPN core
|
||||||
|
// (client reads)
|
||||||
|
struct SessionToken
|
||||||
|
{
|
||||||
|
std::string username;
|
||||||
|
std::string session_id; // an OpenVPN Session ID, used as a proxy for password
|
||||||
|
};
|
||||||
|
|
||||||
|
// used to query challenge/response from user
|
||||||
|
// (client reads)
|
||||||
|
struct DynamicChallenge
|
||||||
|
{
|
||||||
|
std::string challenge;
|
||||||
|
bool echo = false;
|
||||||
|
bool responseRequired = false;
|
||||||
|
|
||||||
|
std::string stateID;
|
||||||
|
};
|
||||||
|
|
||||||
|
// a basic key/value pair, used in Config below when OpenVPN profile is
|
||||||
|
// passed as a dictionary
|
||||||
|
struct KeyValue
|
||||||
|
{
|
||||||
|
KeyValue() {}
|
||||||
|
|
||||||
|
KeyValue(std::string key_arg, std::string value_arg)
|
||||||
|
: key(std::move(key_arg)),
|
||||||
|
value(std::move(value_arg)) {}
|
||||||
|
|
||||||
|
std::string key;
|
||||||
|
std::string value;
|
||||||
|
};
|
||||||
|
|
||||||
|
// OpenVPN config-file/profile
|
||||||
|
// (client writes)
|
||||||
|
struct Config
|
||||||
|
{
|
||||||
|
// OpenVPN profile as a string
|
||||||
|
std::string content;
|
||||||
|
|
||||||
|
// OpenVPN profile as series of key/value pairs (may be provided exclusively
|
||||||
|
// or in addition to content string above).
|
||||||
|
std::vector<KeyValue> contentList;
|
||||||
|
|
||||||
|
// Set to identity OpenVPN GUI version.
|
||||||
|
// Format should be "<gui_identifier><space><version>"
|
||||||
|
// Passed to server as IV_GUI_VER.
|
||||||
|
std::string guiVersion;
|
||||||
|
|
||||||
|
// Use a different server than that specified in "remote"
|
||||||
|
// option of profile
|
||||||
|
std::string serverOverride;
|
||||||
|
|
||||||
|
// Force a given transport protocol
|
||||||
|
// Should be tcp, udp, or adaptive.
|
||||||
|
std::string protoOverride;
|
||||||
|
|
||||||
|
// IPv6 preference
|
||||||
|
// no -- disable IPv6, so tunnel will be IPv4-only
|
||||||
|
// yes -- request combined IPv4/IPv6 tunnel
|
||||||
|
// default (or empty string) -- leave decision to server
|
||||||
|
std::string ipv6;
|
||||||
|
|
||||||
|
// Connection timeout in seconds, or 0 to retry indefinitely
|
||||||
|
int connTimeout = 0;
|
||||||
|
|
||||||
|
// Keep tun interface active during pauses or reconnections
|
||||||
|
bool tunPersist = false;
|
||||||
|
|
||||||
|
// If true and a redirect-gateway profile doesn't also define
|
||||||
|
// DNS servers, use the standard Google DNS servers.
|
||||||
|
bool googleDnsFallback = false;
|
||||||
|
|
||||||
|
// Enable autologin sessions
|
||||||
|
bool autologinSessions = true;
|
||||||
|
|
||||||
|
// An ID used for get-certificate and RSA signing callbacks
|
||||||
|
// for External PKI profiles.
|
||||||
|
std::string externalPkiAlias;
|
||||||
|
|
||||||
|
// If true, don't send client cert/key to peer.
|
||||||
|
bool disableClientCert = false;
|
||||||
|
|
||||||
|
// SSL library debug level
|
||||||
|
int sslDebugLevel = 0;
|
||||||
|
|
||||||
|
// Compression mode, one of:
|
||||||
|
// yes -- allow compression on both uplink and downlink
|
||||||
|
// asym -- allow compression on downlink only (i.e. server -> client)
|
||||||
|
// no (default if empty) -- support compression stubs only
|
||||||
|
std::string compressionMode;
|
||||||
|
|
||||||
|
// private key password (optional)
|
||||||
|
std::string privateKeyPassword;
|
||||||
|
|
||||||
|
// Default key direction parameter for tls-auth (0, 1, or
|
||||||
|
// -1 (bidirectional -- default)) if no key-direction parameter
|
||||||
|
// defined in profile. Generally should be -1 (bidirectional)
|
||||||
|
// for compatibility with 2.x branch
|
||||||
|
int defaultKeyDirection = -1;
|
||||||
|
|
||||||
|
// If true, force ciphersuite to be one of:
|
||||||
|
// 1. TLS_DHE_RSA_WITH_AES_256_CBC_SHA, or
|
||||||
|
// 2. TLS_DHE_RSA_WITH_AES_128_CBC_SHA
|
||||||
|
// and disable setting TLS minimum version.
|
||||||
|
// This is intended for compatibility with legacy systems.
|
||||||
|
bool forceAesCbcCiphersuites = false;
|
||||||
|
|
||||||
|
// Override the minimum TLS version:
|
||||||
|
// disabled -- don't specify a minimum, and disable any minimum
|
||||||
|
// specified in profile
|
||||||
|
// default or "" -- use profile minimum
|
||||||
|
// tls_1_0 -- use TLS 1.0 minimum (overrides profile)
|
||||||
|
// tls_1_1 -- use TLS 1.1 minimum (overrides profile)
|
||||||
|
// tls_1_2 -- use TLS 1.2 minimum (overrides profile)
|
||||||
|
std::string tlsVersionMinOverride;
|
||||||
|
|
||||||
|
// Override or default the tls-cert-profile setting:
|
||||||
|
// default or "" -- use profile default
|
||||||
|
// legacy -- allow 1024-bit RSA certs signed with SHA1
|
||||||
|
// preferred -- require at least 2048-bit RSA certs signed
|
||||||
|
// with SHA256 or higher
|
||||||
|
// suiteb -- require NSA Suite-B
|
||||||
|
// legacy-default -- use legacy as the default if profile
|
||||||
|
// doesn't specify tls-cert-profile
|
||||||
|
// preferred-default -- use preferred as the default if profile
|
||||||
|
// doesn't specify tls-cert-profile
|
||||||
|
std::string tlsCertProfileOverride;
|
||||||
|
|
||||||
|
// Pass custom key/value pairs to OpenVPN server.
|
||||||
|
std::vector<KeyValue> peerInfo;
|
||||||
|
|
||||||
|
// HTTP Proxy parameters (optional)
|
||||||
|
std::string proxyHost; // hostname or IP address of proxy
|
||||||
|
std::string proxyPort; // port number of proxy
|
||||||
|
std::string proxyUsername; // proxy credentials (optional)
|
||||||
|
std::string proxyPassword; // proxy credentials (optional)
|
||||||
|
bool proxyAllowCleartextAuth = false; // enables HTTP Basic auth
|
||||||
|
|
||||||
|
// Custom proxy implementation
|
||||||
|
bool altProxy = false;
|
||||||
|
|
||||||
|
// Custom Data Channel Offload implementation
|
||||||
|
bool dco = false;
|
||||||
|
|
||||||
|
// pass through pushed "echo" directives via "ECHO" event
|
||||||
|
bool echo = false;
|
||||||
|
|
||||||
|
// pass through control channel INFO notifications via "INFO" event
|
||||||
|
bool info = false;
|
||||||
|
|
||||||
|
// Gremlin configuration (requires that the core is built with OPENVPN_GREMLIN)
|
||||||
|
std::string gremlinConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
// used to communicate VPN events such as connect, disconnect, etc.
|
||||||
|
// (client reads)
|
||||||
|
struct Event
|
||||||
|
{
|
||||||
|
bool error = false; // true if error (fatal or nonfatal)
|
||||||
|
bool fatal = false; // true if fatal error (will disconnect)
|
||||||
|
std::string name; // event name
|
||||||
|
std::string info; // additional event info
|
||||||
|
};
|
||||||
|
|
||||||
|
// used to communicate extra details about successful connection
|
||||||
|
// (client reads)
|
||||||
|
struct ConnectionInfo
|
||||||
|
{
|
||||||
|
bool defined = false;
|
||||||
|
std::string user;
|
||||||
|
std::string serverHost;
|
||||||
|
std::string serverPort;
|
||||||
|
std::string serverProto;
|
||||||
|
std::string serverIp;
|
||||||
|
std::string vpnIp4;
|
||||||
|
std::string vpnIp6;
|
||||||
|
std::string gw4;
|
||||||
|
std::string gw6;
|
||||||
|
std::string clientIp;
|
||||||
|
std::string tunName;
|
||||||
|
};
|
||||||
|
|
||||||
|
// returned by some methods as a status/error indication
|
||||||
|
// (client reads)
|
||||||
|
struct Status
|
||||||
|
{
|
||||||
|
bool error = false; // true if error
|
||||||
|
std::string status; // an optional short error label that identifies the error
|
||||||
|
std::string message; // if error, message given here
|
||||||
|
};
|
||||||
|
|
||||||
|
// used to pass log lines
|
||||||
|
// (client reads)
|
||||||
|
struct LogInfo
|
||||||
|
{
|
||||||
|
LogInfo() {}
|
||||||
|
LogInfo(std::string str);
|
||||||
|
std::string text; // log output (usually but not always one line)
|
||||||
|
};
|
||||||
|
|
||||||
|
// receives log messages
|
||||||
|
struct LogReceiver
|
||||||
|
{
|
||||||
|
virtual void log(const LogInfo&) = 0;
|
||||||
|
virtual ~LogReceiver() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// used to pass stats for an interface
|
||||||
|
struct InterfaceStats
|
||||||
|
{
|
||||||
|
long long bytesIn;
|
||||||
|
long long packetsIn;
|
||||||
|
long long errorsIn;
|
||||||
|
long long bytesOut;
|
||||||
|
long long packetsOut;
|
||||||
|
long long errorsOut;
|
||||||
|
};
|
||||||
|
|
||||||
|
// used to pass basic transport stats
|
||||||
|
struct TransportStats
|
||||||
|
{
|
||||||
|
long long bytesIn;
|
||||||
|
long long bytesOut;
|
||||||
|
long long packetsIn;
|
||||||
|
long long packetsOut;
|
||||||
|
|
||||||
|
// number of binary milliseconds (1/1024th of a second) since
|
||||||
|
// last packet was received, or -1 if undefined
|
||||||
|
int lastPacketReceived;
|
||||||
|
};
|
||||||
|
|
||||||
|
// return value of merge_config methods
|
||||||
|
struct MergeConfig
|
||||||
|
{
|
||||||
|
std::string status; // ProfileMerge::Status codes rendered as string
|
||||||
|
std::string errorText; // error string (augments status)
|
||||||
|
std::string basename; // profile basename
|
||||||
|
std::string profileContent; // unified profile
|
||||||
|
std::vector<std::string> refPathList; // list of all reference paths successfully read
|
||||||
|
};
|
||||||
|
|
||||||
|
// base class for External PKI queries
|
||||||
|
struct ExternalPKIRequestBase
|
||||||
|
{
|
||||||
|
bool error = false; // true if error occurred (client writes)
|
||||||
|
std::string errorText; // text describing error (client writes)
|
||||||
|
bool invalidAlias = false; // true if the error is caused by an invalid alias (client writes)
|
||||||
|
std::string alias; // the alias string, used to query cert/key (client reads)
|
||||||
|
};
|
||||||
|
|
||||||
|
// used to query for External PKI certificate
|
||||||
|
struct ExternalPKICertRequest : public ExternalPKIRequestBase
|
||||||
|
{
|
||||||
|
// leaf cert
|
||||||
|
std::string cert; // (client writes)
|
||||||
|
|
||||||
|
// chain of intermediates and root (optional)
|
||||||
|
std::string supportingChain; // (client writes)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Used to request an RSA signature.
|
||||||
|
// Data will be prefixed by an optional PKCS#1 digest prefix
|
||||||
|
// per RFC 3447.
|
||||||
|
struct ExternalPKISignRequest : public ExternalPKIRequestBase
|
||||||
|
{
|
||||||
|
std::string data; // data rendered as base64 (client reads)
|
||||||
|
std::string sig; // RSA signature, rendered as base64 (client writes)
|
||||||
|
};
|
||||||
|
|
||||||
|
// used to override "remote" directives
|
||||||
|
struct RemoteOverride
|
||||||
|
{
|
||||||
|
// components of "remote" directive (client writes),
|
||||||
|
std::string host; // either one of host
|
||||||
|
std::string ip; // or ip must be defined (or both)
|
||||||
|
std::string port;
|
||||||
|
std::string proto;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Private {
|
||||||
|
class ClientState;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Top-level OpenVPN client class.
|
||||||
|
class OpenVPNClient : public TunBuilderBase, public LogReceiver, private ExternalPKIBase {
|
||||||
|
public:
|
||||||
|
OpenVPNClient();
|
||||||
|
virtual ~OpenVPNClient();
|
||||||
|
|
||||||
|
// Call me first, before calling any other method (static or instance methods)
|
||||||
|
// in this class.
|
||||||
|
static void init_process();
|
||||||
|
|
||||||
|
// Release any resources allocated by init_process.
|
||||||
|
static void uninit_process();
|
||||||
|
|
||||||
|
// Read an OpenVPN profile that might contain external
|
||||||
|
// file references, returning a unified profile.
|
||||||
|
static MergeConfig merge_config_static(const std::string& path, bool follow_references);
|
||||||
|
|
||||||
|
// Read an OpenVPN profile that might contain external
|
||||||
|
// file references, returning a unified profile.
|
||||||
|
static MergeConfig merge_config_string_static(const std::string& config_content);
|
||||||
|
|
||||||
|
// Parse profile and determine needed credentials statically.
|
||||||
|
static EvalConfig eval_config_static(const Config& config);
|
||||||
|
|
||||||
|
// Maximum size of profile that should be allowed
|
||||||
|
static long max_profile_size();
|
||||||
|
|
||||||
|
// Parse a dynamic challenge cookie, placing the result in dc.
|
||||||
|
// Return true on success or false if parse error.
|
||||||
|
static bool parse_dynamic_challenge(const std::string& cookie, DynamicChallenge& dc);
|
||||||
|
|
||||||
|
// Parse OpenVPN configuration file.
|
||||||
|
EvalConfig eval_config(const Config&);
|
||||||
|
|
||||||
|
// Provide credentials and other options. Call before connect().
|
||||||
|
Status provide_creds(const ProvideCreds&);
|
||||||
|
|
||||||
|
// Callback to "protect" a socket from being routed through the tunnel.
|
||||||
|
// Will be called from the thread executing connect().
|
||||||
|
virtual bool socket_protect(int socket) = 0;
|
||||||
|
|
||||||
|
// Primary VPN client connect method, doesn't return until disconnect.
|
||||||
|
// Should be called by a worker thread. This method will make callbacks
|
||||||
|
// to event() and log() functions. Make sure to call eval_config()
|
||||||
|
// and possibly provide_creds() as well before this function.
|
||||||
|
Status connect();
|
||||||
|
|
||||||
|
// Return information about the most recent connection. Should be called
|
||||||
|
// after an event of type "CONNECTED".
|
||||||
|
ConnectionInfo connection_info();
|
||||||
|
|
||||||
|
// Writes current session token to tok and returns true.
|
||||||
|
// If session token is unavailable, false is returned and
|
||||||
|
// tok is unmodified.
|
||||||
|
bool session_token(SessionToken& tok);
|
||||||
|
|
||||||
|
// Stop the client. Only meaningful when connect() is running.
|
||||||
|
// May be called asynchronously from a different thread
|
||||||
|
// when connect() is running.
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
// Pause the client -- useful to avoid continuous reconnection attempts
|
||||||
|
// when network is down. May be called from a different thread
|
||||||
|
// when connect() is running.
|
||||||
|
void pause(const std::string& reason);
|
||||||
|
|
||||||
|
// Resume the client after it has been paused. May be called from a
|
||||||
|
// different thread when connect() is running.
|
||||||
|
void resume();
|
||||||
|
|
||||||
|
// Do a disconnect/reconnect cycle n seconds from now. May be called
|
||||||
|
// from a different thread when connect() is running.
|
||||||
|
void reconnect(int seconds);
|
||||||
|
|
||||||
|
// When a connection is close to timeout, the core will call this
|
||||||
|
// method. If it returns false, the core will disconnect with a
|
||||||
|
// CONNECTION_TIMEOUT event. If true, the core will enter a PAUSE
|
||||||
|
// state.
|
||||||
|
virtual bool pause_on_connection_timeout() = 0;
|
||||||
|
|
||||||
|
// Get stats/error info. May be called from a different thread
|
||||||
|
// when connect() is running.
|
||||||
|
|
||||||
|
// number of stats
|
||||||
|
static int stats_n();
|
||||||
|
|
||||||
|
// return a stats name, index should be >= 0 and < stats_n()
|
||||||
|
static std::string stats_name(int index);
|
||||||
|
|
||||||
|
// return a stats value, index should be >= 0 and < stats_n()
|
||||||
|
long long stats_value(int index) const;
|
||||||
|
|
||||||
|
// return all stats in a bundle
|
||||||
|
std::vector<long long> stats_bundle() const;
|
||||||
|
|
||||||
|
// return tun stats only
|
||||||
|
InterfaceStats tun_stats() const;
|
||||||
|
|
||||||
|
// return transport stats only
|
||||||
|
TransportStats transport_stats() const;
|
||||||
|
|
||||||
|
// post control channel message
|
||||||
|
void post_cc_msg(const std::string& msg);
|
||||||
|
|
||||||
|
// Callback for delivering events during connect() call.
|
||||||
|
// Will be called from the thread executing connect().
|
||||||
|
virtual void event(const Event&) = 0;
|
||||||
|
|
||||||
|
// Callback for logging.
|
||||||
|
// Will be called from the thread executing connect().
|
||||||
|
virtual void log(const LogInfo&) = 0;
|
||||||
|
|
||||||
|
// External PKI callbacks
|
||||||
|
// Will be called from the thread executing connect().
|
||||||
|
virtual void external_pki_cert_request(ExternalPKICertRequest&) = 0;
|
||||||
|
virtual void external_pki_sign_request(ExternalPKISignRequest&) = 0;
|
||||||
|
|
||||||
|
// Remote override callback (disabled by default).
|
||||||
|
virtual bool remote_override_enabled();
|
||||||
|
virtual void remote_override(RemoteOverride&);
|
||||||
|
|
||||||
|
// Do a crypto library self test
|
||||||
|
static std::string crypto_self_test();
|
||||||
|
|
||||||
|
// Returns date/time of app expiration as a unix time value
|
||||||
|
static int app_expire();
|
||||||
|
|
||||||
|
// Returns platform description string
|
||||||
|
static std::string platform();
|
||||||
|
|
||||||
|
// Returns core copyright
|
||||||
|
static std::string copyright();
|
||||||
|
|
||||||
|
// Hide protected methods/data from SWIG
|
||||||
|
#ifdef SWIGJAVA
|
||||||
|
private:
|
||||||
|
#else
|
||||||
|
protected:
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Status do_connect();
|
||||||
|
|
||||||
|
virtual void connect_attach();
|
||||||
|
virtual void connect_pre_run();
|
||||||
|
virtual void connect_run();
|
||||||
|
virtual void connect_session_stop();
|
||||||
|
|
||||||
|
virtual Stop* get_async_stop();
|
||||||
|
|
||||||
|
Private::ClientState* state;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void parse_config(const Config&, EvalConfig&, OptionList&);
|
||||||
|
void parse_extras(const Config&, EvalConfig&);
|
||||||
|
void external_pki_error(const ExternalPKIRequestBase&, const size_t err_type);
|
||||||
|
void process_epki_cert_chain(const ExternalPKICertRequest& req);
|
||||||
|
void check_app_expired();
|
||||||
|
static MergeConfig build_merge_config(const ProfileMerge&);
|
||||||
|
|
||||||
|
// from ExternalPKIBase
|
||||||
|
virtual bool sign(const std::string& data, std::string& sig);
|
||||||
|
|
||||||
|
// disable copy and assignment
|
||||||
|
OpenVPNClient(const OpenVPNClient&) = delete;
|
||||||
|
OpenVPNClient& operator=(const OpenVPNClient&) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
if [ -z "$O3" ]; then
|
||||||
|
echo O3 var must point to ovpn3 tree
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -z "$DL" ] && DL=~/Downloads
|
||||||
|
|
||||||
|
. $O3/core/deps/lib-versions
|
||||||
|
|
||||||
|
rm -rf asio*
|
||||||
|
tar xf $DL/$ASIO_VERSION.tar.gz
|
||||||
|
cp -a $ASIO_VERSION asio
|
||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
From 430862dee0dd960be1f702cc5ae0e7c0525d48a4 Mon Sep 17 00:00:00 2001
|
||||||
|
From: James Yonan <james@openvpn.net>
|
||||||
|
Date: Wed, 3 Aug 2016 11:42:38 -0600
|
||||||
|
Subject: =?UTF-8?q?Added=20Apple=20NAT64=20support=20when=20both=20ASIO=5F?=
|
||||||
|
=?UTF-8?q?HAS=5FGETADDRINFO=0Aand=20ASIO=5FAPPLE=5FNAT64=20are=20defined.?=
|
||||||
|
|
||||||
|
* When calling getaddrinfo(), Apple recommends to set
|
||||||
|
AI_DEFAULT flags in hint.
|
||||||
|
|
||||||
|
* iOS bug workaround: sometimes iOS getaddrinfo() returns a
|
||||||
|
non-zero scope ID for non-link-local addresses.
|
||||||
|
Workaround by forcing scope ID to 0 for non-link-local
|
||||||
|
addresses.
|
||||||
|
---
|
||||||
|
asio/include/asio/detail/impl/socket_ops.ipp | 17 +++++++++++++++++
|
||||||
|
1 file changed, 17 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/asio/include/asio/detail/impl/socket_ops.ipp b/asio/include/asio/detail/impl/socket_ops.ipp
|
||||||
|
index d72afec..4f66c77 100644
|
||||||
|
--- a/asio/include/asio/detail/impl/socket_ops.ipp
|
||||||
|
+++ b/asio/include/asio/detail/impl/socket_ops.ipp
|
||||||
|
@@ -3276,6 +3276,23 @@ asio::error_code getaddrinfo(const char* host,
|
||||||
|
#elif !defined(ASIO_HAS_GETADDRINFO)
|
||||||
|
int error = getaddrinfo_emulation(host, service, &hints, result);
|
||||||
|
return ec = translate_addrinfo_error(error);
|
||||||
|
+#elif defined(ASIO_HAS_GETADDRINFO) && defined(ASIO_APPLE_NAT64)
|
||||||
|
+ // For NAT64 compatibility, Apple recommends to set AI_DEFAULT flags
|
||||||
|
+ addrinfo_type new_hints = hints;
|
||||||
|
+ new_hints.ai_flags |= AI_DEFAULT;
|
||||||
|
+ int error = ::getaddrinfo(host, service, &new_hints, result);
|
||||||
|
+
|
||||||
|
+ // iOS bug workaround: sometimes iOS getaddrinfo() returns a non-zero scope ID
|
||||||
|
+ // for non-link-local addresses. Workaround by forcing scope ID to 0 for
|
||||||
|
+ // non-link-local addresses.
|
||||||
|
+ if (!error && (*result)->ai_family == AF_INET6)
|
||||||
|
+ {
|
||||||
|
+ sockaddr_in6* a6 = (sockaddr_in6*)(*result)->ai_addr;
|
||||||
|
+ if (a6->sin6_scope_id && !(IN6_IS_ADDR_LINKLOCAL(&a6->sin6_addr) || IN6_IS_ADDR_MC_NODELOCAL(&a6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&a6->sin6_addr)))
|
||||||
|
+ a6->sin6_scope_id = 0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return ec = translate_addrinfo_error(error);
|
||||||
|
#else
|
||||||
|
int error = ::getaddrinfo(host, service, &hints, result);
|
||||||
|
return ec = translate_addrinfo_error(error);
|
||||||
|
--
|
||||||
|
1.8.5.2 (Apple Git-48)
|
||||||
|
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
From d1758fee525c6adde63ff13df1ce00c63a9b7671 Mon Sep 17 00:00:00 2001
|
||||||
|
From: James Yonan <james@openvpn.net>
|
||||||
|
Date: Wed, 2 Sep 2015 12:18:48 -0700
|
||||||
|
Subject: Added randomize() method to asio::ip::tcp::resolver::results_type.
|
||||||
|
|
||||||
|
---
|
||||||
|
asio/include/asio/ip/basic_resolver_results.hpp | 7 +++++++
|
||||||
|
1 file changed, 7 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/asio/include/asio/ip/basic_resolver_results.hpp b/asio/include/asio/ip/basic_resolver_results.hpp
|
||||||
|
index dec2c7e..ae36906 100644
|
||||||
|
--- a/asio/include/asio/ip/basic_resolver_results.hpp
|
||||||
|
+++ b/asio/include/asio/ip/basic_resolver_results.hpp
|
||||||
|
@@ -18,6 +18,7 @@
|
||||||
|
#include "asio/detail/config.hpp"
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstring>
|
||||||
|
+#include <algorithm>
|
||||||
|
#include "asio/detail/socket_ops.hpp"
|
||||||
|
#include "asio/detail/socket_types.hpp"
|
||||||
|
#include "asio/ip/basic_resolver_iterator.hpp"
|
||||||
|
@@ -299,6 +300,12 @@ public:
|
||||||
|
return !a.equal(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ template <typename Random>
|
||||||
|
+ void randomize(Random& r)
|
||||||
|
+ {
|
||||||
|
+ std::shuffle(this->values_->begin(), this->values_->end(), r);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
private:
|
||||||
|
typedef std::vector<basic_resolver_entry<InternetProtocol> > values_type;
|
||||||
|
};
|
||||||
|
--
|
||||||
|
1.8.5.2 (Apple Git-48)
|
||||||
|
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
From 48f2e874280f0d93d1a3df2e48aacc9e13b8eef5 Mon Sep 17 00:00:00 2001
|
||||||
|
From: James Yonan <james@openvpn.net>
|
||||||
|
Date: Wed, 1 Mar 2017 13:45:38 -0700
|
||||||
|
Subject: Android appears to not support pthread_condattr_setclock
|
||||||
|
|
||||||
|
---
|
||||||
|
asio/include/asio/detail/impl/posix_event.ipp | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/asio/include/asio/detail/impl/posix_event.ipp b/asio/include/asio/detail/impl/posix_event.ipp
|
||||||
|
index a62c434..c4b7982 100644
|
||||||
|
--- a/asio/include/asio/detail/impl/posix_event.ipp
|
||||||
|
+++ b/asio/include/asio/detail/impl/posix_event.ipp
|
||||||
|
@@ -31,7 +31,7 @@ namespace detail {
|
||||||
|
posix_event::posix_event()
|
||||||
|
: state_(0)
|
||||||
|
{
|
||||||
|
-#if (defined(__MACH__) && defined(__APPLE__))
|
||||||
|
+#if (defined(__MACH__) && defined(__APPLE__)) || defined(__ANDROID__)
|
||||||
|
int error = ::pthread_cond_init(&cond_, 0);
|
||||||
|
#else // (defined(__MACH__) && defined(__APPLE__))
|
||||||
|
::pthread_condattr_t attr;
|
||||||
|
--
|
||||||
|
2.7.4
|
||||||
|
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
From 630edbebfc2f77ad29480d884e20d0b767883ac2 Mon Sep 17 00:00:00 2001
|
||||||
|
From: James Yonan <james@openvpn.net>
|
||||||
|
Date: Mon, 27 Feb 2017 13:01:26 -0700
|
||||||
|
Subject: =?UTF-8?q?Added=20user=20code=20hook=20async=5Fconnect=5Fpost=5Fo?=
|
||||||
|
=?UTF-8?q?pen()=20to=20be=20called=0Aimmediately=20after=20socket=20open?=
|
||||||
|
=?UTF-8?q?=20in=20async=5Fconnect.?=
|
||||||
|
|
||||||
|
---
|
||||||
|
asio/include/asio/basic_socket.hpp | 7 +++++++
|
||||||
|
1 file changed, 7 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/asio/include/asio/basic_socket.hpp b/asio/include/asio/basic_socket.hpp
|
||||||
|
index cbd9b35..dbc9297 100644
|
||||||
|
--- a/asio/include/asio/basic_socket.hpp
|
||||||
|
+++ b/asio/include/asio/basic_socket.hpp
|
||||||
|
@@ -866,6 +866,8 @@ public:
|
||||||
|
asio::error_code ec;
|
||||||
|
const protocol_type protocol = peer_endpoint.protocol();
|
||||||
|
this->get_service().open(this->get_implementation(), protocol, ec);
|
||||||
|
+ if (!ec)
|
||||||
|
+ async_connect_post_open(protocol, ec);
|
||||||
|
if (ec)
|
||||||
|
{
|
||||||
|
async_completion<ConnectHandler,
|
||||||
|
@@ -1742,6 +1744,11 @@ protected:
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
+ // optional user code hook immediately after socket open in async_connect
|
||||||
|
+ virtual void async_connect_post_open(const protocol_type& protocol, asio::error_code& ec)
|
||||||
|
+ {
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
// Disallow copying and assignment.
|
||||||
|
basic_socket(const basic_socket&) ASIO_DELETED;
|
||||||
|
basic_socket& operator=(const basic_socket&) ASIO_DELETED;
|
||||||
|
--
|
||||||
|
1.8.5.2 (Apple Git-48)
|
||||||
|
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
export NAME=asio
|
||||||
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
$DIR/../../scripts/snapshot
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
--- boost/atomic/detail/cas128strong.hpp
|
||||||
|
+++ boost/atomic/detail/cas128strong.hpp
|
||||||
|
@@ -196,15 +196,17 @@ class base_atomic<T, void, 16, Sign>
|
||||||
|
|
||||||
|
public:
|
||||||
|
BOOST_DEFAULTED_FUNCTION(base_atomic(void), {})
|
||||||
|
- explicit base_atomic(value_type const& v) BOOST_NOEXCEPT : v_(0)
|
||||||
|
+ explicit base_atomic(value_type const& v) BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
+ memset(&v_, 0, sizeof(v_));
|
||||||
|
memcpy(&v_, &v, sizeof(value_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
store(value_type const& value, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
- storage_type value_s = 0;
|
||||||
|
+ storage_type value_s;
|
||||||
|
+ memset(&value_s, 0, sizeof(value_s));
|
||||||
|
memcpy(&value_s, &value, sizeof(value_type));
|
||||||
|
platform_fence_before_store(order);
|
||||||
|
platform_store128(value_s, &v_);
|
||||||
|
@@ -247,7 +249,9 @@ class base_atomic<T, void, 16, Sign>
|
||||||
|
memory_order success_order,
|
||||||
|
memory_order failure_order) volatile BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
- storage_type expected_s = 0, desired_s = 0;
|
||||||
|
+ storage_type expected_s, desired_s;
|
||||||
|
+ memset(&expected_s, 0, sizeof(expected_s));
|
||||||
|
+ memset(&desired_s, 0, sizeof(desired_s));
|
||||||
|
memcpy(&expected_s, &expected, sizeof(value_type));
|
||||||
|
memcpy(&desired_s, &desired, sizeof(value_type));
|
||||||
|
|
||||||
|
--- boost/atomic/detail/gcc-atomic.hpp
|
||||||
|
+++ boost/atomic/detail/gcc-atomic.hpp
|
||||||
|
@@ -958,14 +958,16 @@ class base_atomic<T, void, 16, Sign>
|
||||||
|
|
||||||
|
public:
|
||||||
|
BOOST_DEFAULTED_FUNCTION(base_atomic(void), {})
|
||||||
|
- explicit base_atomic(value_type const& v) BOOST_NOEXCEPT : v_(0)
|
||||||
|
+ explicit base_atomic(value_type const& v) BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
+ memset(&v_, 0, sizeof(v_));
|
||||||
|
memcpy(&v_, &v, sizeof(value_type));
|
||||||
|
}
|
||||||
|
|
||||||
|
void store(value_type const& v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
- storage_type tmp = 0;
|
||||||
|
+ storage_type tmp;
|
||||||
|
+ memset(&tmp, 0, sizeof(tmp));
|
||||||
|
memcpy(&tmp, &v, sizeof(value_type));
|
||||||
|
__atomic_store_n(&v_, tmp, atomics::detail::convert_memory_order_to_gcc(order));
|
||||||
|
}
|
||||||
|
@@ -980,7 +982,8 @@ class base_atomic<T, void, 16, Sign>
|
||||||
|
|
||||||
|
value_type exchange(value_type const& v, memory_order order = memory_order_seq_cst) volatile BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
- storage_type tmp = 0;
|
||||||
|
+ storage_type tmp;
|
||||||
|
+ memset(&tmp, 0, sizeof(tmp));
|
||||||
|
memcpy(&tmp, &v, sizeof(value_type));
|
||||||
|
tmp = __atomic_exchange_n(&v_, tmp, atomics::detail::convert_memory_order_to_gcc(order));
|
||||||
|
value_type res;
|
||||||
|
@@ -994,7 +997,9 @@ class base_atomic<T, void, 16, Sign>
|
||||||
|
memory_order success_order,
|
||||||
|
memory_order failure_order) volatile BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
- storage_type expected_s = 0, desired_s = 0;
|
||||||
|
+ storage_type expected_s, desired_s;
|
||||||
|
+ memset(&expected_s, 0, sizeof(expected_s));
|
||||||
|
+ memset(&desired_s, 0, sizeof(desired_s));
|
||||||
|
memcpy(&expected_s, &expected, sizeof(value_type));
|
||||||
|
memcpy(&desired_s, &desired, sizeof(value_type));
|
||||||
|
const bool success = __atomic_compare_exchange_n(&v_, &expected_s, desired_s, false,
|
||||||
|
@@ -1010,7 +1015,9 @@ class base_atomic<T, void, 16, Sign>
|
||||||
|
memory_order success_order,
|
||||||
|
memory_order failure_order) volatile BOOST_NOEXCEPT
|
||||||
|
{
|
||||||
|
- storage_type expected_s = 0, desired_s = 0;
|
||||||
|
+ storage_type expected_s, desired_s;
|
||||||
|
+ memset(&expected_s, 0, sizeof(expected_s));
|
||||||
|
+ memset(&desired_s, 0, sizeof(desired_s));
|
||||||
|
memcpy(&expected_s, &expected, sizeof(value_type));
|
||||||
|
memcpy(&desired_s, &desired, sizeof(value_type));
|
||||||
|
const bool success = __atomic_compare_exchange_n(&v_, &expected_s, desired_s, true,
|
||||||
|
--
|
||||||
+75
@@ -0,0 +1,75 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Parameters:
|
||||||
|
# SDK_PATH_SCRIPT -- optional script to set SDK path
|
||||||
|
|
||||||
|
set -e
|
||||||
|
if [ -z "$O3" ]; then
|
||||||
|
echo O3 var must point to ovpn3 tree
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -z "$TARGETS" ]; then
|
||||||
|
echo TARGETS var must be defined
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# NOTE: in Boost 1.55 and earlier, set BCONF=tools/build/v2
|
||||||
|
BCONF=tools/build/src
|
||||||
|
|
||||||
|
. $O3/core/deps/lib-versions
|
||||||
|
[ -z "$DL" ] && DL=~/Downloads
|
||||||
|
[ -z "$GPP_CMD" ] && export GPP_CMD=g++
|
||||||
|
[ -z "$GCC_CMD" ] && export GCC_CMD=gcc
|
||||||
|
if [ "$NO_WIPE" != "1" ]; then
|
||||||
|
echo WIPE and reunzip source
|
||||||
|
rm -rf boost $BOOST_VERSION
|
||||||
|
mkdir boost
|
||||||
|
tar xfz $DL/$BOOST_VERSION.tar.gz
|
||||||
|
cd $BOOST_VERSION
|
||||||
|
#patch -p1 <$DL/asio-engine.patch
|
||||||
|
#patch -p0 <$O3/core/deps/boost/atomic-1.55.0.patch
|
||||||
|
patch -p1 <$O3/core/deps/boost/intrusive_ptr.patch
|
||||||
|
patch -p1 <$O3/core/deps/boost/page_size.patch
|
||||||
|
|
||||||
|
./bootstrap.sh
|
||||||
|
|
||||||
|
for T in $TARGETS ; do
|
||||||
|
TS="${T//-/}"
|
||||||
|
. $O3/core/vars/vars-$T
|
||||||
|
cat >>$BCONF/user-config.jam <<EOF
|
||||||
|
using $GCC_CMD : $TS : $GPP_CMD
|
||||||
|
:
|
||||||
|
<compileflags>"-Wno-unused-function $PLATFORM_FLAGS $CXX_COMPILER_FLAGS $OTHER_COMPILER_FLAGS $LIB_FPIC $LIB_OPT_LEVEL"
|
||||||
|
;
|
||||||
|
EOF
|
||||||
|
done
|
||||||
|
echo '********** BOOST CONFIG'
|
||||||
|
tail -30 $BCONF/user-config.jam
|
||||||
|
echo '********** END BOOST CONFIG'
|
||||||
|
else
|
||||||
|
echo RETAIN existing source
|
||||||
|
cd $BOOST_VERSION
|
||||||
|
for T in $TARGETS ; do
|
||||||
|
TS="${T//-/}"
|
||||||
|
. $O3/core/vars/vars-$T
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
[ "$SDK_PATH_SCRIPT" ] && . $SDK_PATH_SCRIPT
|
||||||
|
for T in $TARGETS ; do
|
||||||
|
. $O3/core/vars/vars-$T
|
||||||
|
target="${T//-/}"
|
||||||
|
stage=stage-$T
|
||||||
|
if [ "${target:(-3)}" == "dbg" ]; then
|
||||||
|
variant=debug
|
||||||
|
else
|
||||||
|
variant=release
|
||||||
|
fi
|
||||||
|
[ -z "$LINK_MODE" ] && LINK_MODE=static
|
||||||
|
echo "************************ $target $variant $stage"
|
||||||
|
cmd="./bjam -d2 toolset=${GCC_CMD}-${target} --stagedir=$stage --with-system --with-thread --with-atomic variant=$variant link=$LINK_MODE threading=multi runtime-link=$LINK_MODE"
|
||||||
|
echo $cmd
|
||||||
|
$cmd
|
||||||
|
done
|
||||||
|
mv stage-* ../boost/
|
||||||
|
cp -a boost ../boost/
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
diff -ur boost_1_56_0.orig/boost/smart_ptr/intrusive_ptr.hpp boost_1_56_0/boost/smart_ptr/intrusive_ptr.hpp
|
||||||
|
--- boost_1_56_0.orig/boost/smart_ptr/intrusive_ptr.hpp 2014-07-26 00:44:34.000000000 -0600
|
||||||
|
+++ boost_1_56_0/boost/smart_ptr/intrusive_ptr.hpp 2014-08-15 19:51:11.000000000 -0600
|
||||||
|
@@ -63,7 +63,7 @@
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- intrusive_ptr( T * p, bool add_ref = true ): px( p )
|
||||||
|
+ intrusive_ptr( T * p, bool add_ref = true ) BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(intrusive_ptr_add_ref(static_cast<T*>(nullptr)))) : px( p )
|
||||||
|
{
|
||||||
|
if( px != 0 && add_ref ) intrusive_ptr_add_ref( px );
|
||||||
|
}
|
||||||
|
@@ -80,14 +80,14 @@
|
||||||
|
intrusive_ptr( intrusive_ptr<U> const & rhs )
|
||||||
|
|
||||||
|
#endif
|
||||||
|
- : px( rhs.get() )
|
||||||
|
+ BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(intrusive_ptr_add_ref(static_cast<T*>(nullptr)))) : px( rhs.get() )
|
||||||
|
{
|
||||||
|
if( px != 0 ) intrusive_ptr_add_ref( px );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
- intrusive_ptr(intrusive_ptr const & rhs): px( rhs.px )
|
||||||
|
+ intrusive_ptr(intrusive_ptr const & rhs) BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(intrusive_ptr_add_ref(static_cast<T*>(nullptr)))) : px( rhs.px )
|
||||||
|
{
|
||||||
|
if( px != 0 ) intrusive_ptr_add_ref( px );
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
diff -ur boost_1_57_0/boost/thread/pthread/thread_data.hpp boost_1_57_0.new/boost/thread/pthread/thread_data.hpp
|
||||||
|
--- boost_1_57_0/boost/thread/pthread/thread_data.hpp 2014-10-24 10:43:26.000000000 -0600
|
||||||
|
+++ boost_1_57_0.new/boost/thread/pthread/thread_data.hpp 2015-02-26 00:43:26.000000000 -0700
|
||||||
|
@@ -24,8 +24,10 @@
|
||||||
|
#include <vector>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
-#if defined(__ANDROID__)
|
||||||
|
-#include <asm/page.h> // http://code.google.com/p/android/issues/detail?id=39983
|
||||||
|
+// JY modified
|
||||||
|
+#if defined(__ANDROID__) && !defined(PAGE_SIZE)
|
||||||
|
+#define PAGE_SIZE 4096
|
||||||
|
+//#include <asm/page.h> // http://code.google.com/p/android/issues/detail?id=39983
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
export ASIO_VERSION=asio-20170301
|
||||||
|
export LZ4_VERSION=lz4-1.7.5
|
||||||
|
export MBEDTLS_VERSION=mbedtls-2.4.0
|
||||||
|
export OPENSSL_VERSION=openssl-1.0.2h
|
||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
if [ -z "$O3" ]; then
|
||||||
|
echo O3 var must point to ovpn3 tree
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -z "$TARGET" ]; then
|
||||||
|
echo TARGET var must be defined
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -z "$DL" ] && DL=~/Downloads
|
||||||
|
|
||||||
|
# source vars
|
||||||
|
. $O3/core/vars/vars-${TARGET}
|
||||||
|
. $O3/core/deps/lib-versions
|
||||||
|
|
||||||
|
|
||||||
|
CC=cc
|
||||||
|
LD=ld
|
||||||
|
AR=ar
|
||||||
|
RANLIB=ranlib
|
||||||
|
[ "$GCC_CMD" ] && CC=$GCC_CMD
|
||||||
|
[ "$LD_CMD" ] && LD=$LD_CMD
|
||||||
|
[ "$AR_CMD" ] && AR=$AR_CMD
|
||||||
|
[ "$RANLIB_CMD" ] && RANLIB=$RANLIB_CMD
|
||||||
|
|
||||||
|
if [ "$NO_WIPE" != "1" ]; then
|
||||||
|
rm -rf $LZ4_VERSION
|
||||||
|
tar xfz $DL/$LZ4_VERSION.tar.gz
|
||||||
|
fi
|
||||||
|
|
||||||
|
DIST=$(pwd)/lz4/lz4-$PLATFORM
|
||||||
|
rm -rf $DIST
|
||||||
|
mkdir -p $DIST/include
|
||||||
|
mkdir $DIST/lib
|
||||||
|
cd $LZ4_VERSION/lib
|
||||||
|
CMD="$CC $PLATFORM_FLAGS $OTHER_COMPILER_FLAGS $LIB_OPT_LEVEL $LIB_FPIC -c lz4.c"
|
||||||
|
echo $CMD
|
||||||
|
$CMD
|
||||||
|
$AR rc $DIST/lib/liblz4.a lz4.o
|
||||||
|
$RANLIB $DIST/lib/liblz4.a
|
||||||
|
cp lz4.h $DIST/include/
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
export NAME=lz4
|
||||||
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||||
|
$DIR/../../scripts/snapshot
|
||||||
+62
@@ -0,0 +1,62 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
if [ -z "$O3" ]; then
|
||||||
|
echo O3 var must point to ovpn3 tree
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -z "$TARGET" ]; then
|
||||||
|
echo TARGET var must be defined
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -z "$DL" ] && DL=~/Downloads
|
||||||
|
|
||||||
|
# source vars
|
||||||
|
. $O3/core/vars/vars-${TARGET}
|
||||||
|
. $O3/core/deps/lib-versions
|
||||||
|
|
||||||
|
[ "$GCC_CMD" ] && export CC=$GCC_CMD
|
||||||
|
[ "$LD_CMD" ] && export LD=$LD_CMD
|
||||||
|
[ "$AR_CMD" ] && export AR=$AR_CMD
|
||||||
|
[ "$RANLIB_CMD" ] && export RANLIB=$RANLIB_CMD
|
||||||
|
|
||||||
|
case $PLATFORM in
|
||||||
|
android*)
|
||||||
|
echo PLATFORM android
|
||||||
|
host=arm
|
||||||
|
target=arm
|
||||||
|
;;
|
||||||
|
ios*)
|
||||||
|
echo PLATFORM ios
|
||||||
|
host="x86_64-apple-darwin"
|
||||||
|
target=arm
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
host=""
|
||||||
|
target=""
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ "$target" ]; then
|
||||||
|
targ_opt="--target=$target"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$host" ]; then
|
||||||
|
host_opt="--host=$host"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$NO_WIPE" != "1" ]; then
|
||||||
|
rm -rf $LZO_VERSION
|
||||||
|
tar xfz $DL/$LZO_VERSION.tar.gz
|
||||||
|
fi
|
||||||
|
|
||||||
|
DIST=$(pwd)/lzo/lzo-$PLATFORM
|
||||||
|
rm -rf $DIST
|
||||||
|
mkdir -p $DIST
|
||||||
|
cd $LZO_VERSION
|
||||||
|
echo 'OPTIONS' $CC $LD $AR $RANLIB $host_opt $targ_opt
|
||||||
|
CFLAGS="$PLATFORM_FLAGS $OTHER_COMPILER_FLAGS $LIB_OPT_LEVEL $LIB_FPIC" ./configure --prefix=$DIST $host_opt $targ_opt
|
||||||
|
make
|
||||||
|
make install
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
if [ -z "$O3" ]; then
|
||||||
|
echo O3 var must point to ovpn3 tree
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -z "$TARGET" ]; then
|
||||||
|
echo TARGET var must be defined
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# source vars
|
||||||
|
. $O3/core/vars/vars-${TARGET}
|
||||||
|
. $O3/core/deps/lib-versions
|
||||||
|
|
||||||
|
# put build targets here
|
||||||
|
DIST=$(pwd)/mbedtls/mbedtls-$PLATFORM
|
||||||
|
rm -rf $DIST
|
||||||
|
mkdir -p $DIST
|
||||||
|
|
||||||
|
if [ "$NO_WIPE" = "1" ]; then
|
||||||
|
echo RETAIN existing source
|
||||||
|
cd $MBEDTLS_VERSION
|
||||||
|
else
|
||||||
|
echo WIPE and reunzip source
|
||||||
|
rm -rf $MBEDTLS_VERSION
|
||||||
|
[ -z "$DL" ] && DL=~/Downloads
|
||||||
|
tar xfz $DL/$MBEDTLS_VERSION-apache.tgz
|
||||||
|
cd $MBEDTLS_VERSION
|
||||||
|
|
||||||
|
# enable MD4 (needed for NTLM auth)
|
||||||
|
perl -pi -e 's/^\/\/// if /#define MBEDTLS_MD4_C/' include/mbedtls/config.h
|
||||||
|
fi
|
||||||
|
|
||||||
|
# compiler vars
|
||||||
|
CC=cc
|
||||||
|
LD=ld
|
||||||
|
AR=ar
|
||||||
|
RANLIB=ranlib
|
||||||
|
[ "$GCC_CMD" ] && CC=$GCC_CMD
|
||||||
|
[ "$LD_CMD" ] && LD=$LD_CMD
|
||||||
|
[ "$AR_CMD" ] && AR=$AR_CMD
|
||||||
|
[ "$RANLIB_CMD" ] && RANLIB=$RANLIB_CMD
|
||||||
|
|
||||||
|
# build it
|
||||||
|
SRC=$(pwd)
|
||||||
|
cd library
|
||||||
|
rm -f *.o
|
||||||
|
for c in *.c ; do
|
||||||
|
CMD="$CC -I../include $PLATFORM_FLAGS $OTHER_COMPILER_FLAGS $LIB_OPT_LEVEL $LIB_FPIC -c $c"
|
||||||
|
echo $CMD
|
||||||
|
$CMD
|
||||||
|
done
|
||||||
|
|
||||||
|
# create archive
|
||||||
|
cd $DIST
|
||||||
|
mkdir library
|
||||||
|
$AR rc library/libmbedtls.a $SRC/library/*.o
|
||||||
|
$RANLIB library/libmbedtls.a 2>&1 | grep -v "has no symbols" || true
|
||||||
|
|
||||||
|
# copy headers
|
||||||
|
mkdir -p include/mbedtls
|
||||||
|
cp $SRC/include/mbedtls/*.h include/mbedtls/
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
--- aes-armv4.pl.orig 2012-09-03 00:16:20.000000000 -0600
|
||||||
|
+++ aes-armv4.pl 2012-09-03 00:17:22.000000000 -0600
|
||||||
|
@@ -171,7 +170,8 @@
|
||||||
|
stmdb sp!,{r1,r4-r12,lr}
|
||||||
|
mov $rounds,r0 @ inp
|
||||||
|
mov $key,r2
|
||||||
|
- sub $tbl,r3,#AES_encrypt-AES_Te @ Te
|
||||||
|
+ad1=AES_encrypt-AES_Te
|
||||||
|
+ sub $tbl,r3,#ad1 @ Te
|
||||||
|
#if __ARM_ARCH__<7
|
||||||
|
ldrb $s0,[$rounds,#3] @ load input data in endian-neutral
|
||||||
|
ldrb $t1,[$rounds,#2] @ manner...
|
||||||
|
@@ -426,7 +426,8 @@
|
||||||
|
bne .Labrt
|
||||||
|
|
||||||
|
.Lok: stmdb sp!,{r4-r12,lr}
|
||||||
|
- sub $tbl,r3,#_armv4_AES_set_encrypt_key-AES_Te-1024 @ Te4
|
||||||
|
+ad2=_armv4_AES_set_encrypt_key-AES_Te-1024
|
||||||
|
+ sub $tbl,r3,#ad2 @ Te4
|
||||||
|
|
||||||
|
mov $rounds,r0 @ inp
|
||||||
|
mov lr,r1 @ bits
|
||||||
|
@@ -887,7 +888,8 @@
|
||||||
|
stmdb sp!,{r1,r4-r12,lr}
|
||||||
|
mov $rounds,r0 @ inp
|
||||||
|
mov $key,r2
|
||||||
|
- sub $tbl,r3,#AES_decrypt-AES_Td @ Td
|
||||||
|
+ad3=AES_decrypt-AES_Td
|
||||||
|
+ sub $tbl,r3,#ad3 @ Td
|
||||||
|
#if __ARM_ARCH__<7
|
||||||
|
ldrb $s0,[$rounds,#3] @ load input data in endian-neutral
|
||||||
|
ldrb $t1,[$rounds,#2] @ manner...
|
||||||
@@ -0,0 +1,759 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# arm-as-to-ios Modify ARM assembly code for the iOS assembler
|
||||||
|
#
|
||||||
|
# Copyright (c) 2012 Psellos http://psellos.com/
|
||||||
|
# Licensed under the MIT License:
|
||||||
|
# http://www.opensource.org/licenses/mit-license.php
|
||||||
|
#
|
||||||
|
# Resources for running OCaml on iOS: http://psellos.com/ocaml/
|
||||||
|
#
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
|
||||||
|
VERSION = '1.4.0'
|
||||||
|
|
||||||
|
initial_glosyms = []
|
||||||
|
initial_defsyms = []
|
||||||
|
|
||||||
|
# Character classes for expression lexing.
|
||||||
|
#
|
||||||
|
g_ccid0 = '[$.A-Z_a-z\x80-\xff]' # Beginning of id
|
||||||
|
g_ccid = '[$.0-9A-Z_a-z\x80-\xff]' # Later in id
|
||||||
|
def ccc(cc): # Complement the class
|
||||||
|
if cc[1] == '^':
|
||||||
|
return cc[0] + cc[2:]
|
||||||
|
return cc[0] + '^' + cc[1:]
|
||||||
|
def ccce(cc): # Complement the class, include EOL
|
||||||
|
return '(?:' + ccc(cc) + '|$)'
|
||||||
|
|
||||||
|
# Prefixes for pooled symbol labels and jump table base labels. They're
|
||||||
|
# in the space of Linux assembler local symbols. Later rules will
|
||||||
|
# modify them to the Loc() form.
|
||||||
|
#
|
||||||
|
g_poolpfx = '.LP'
|
||||||
|
g_basepfx = '.LB'
|
||||||
|
|
||||||
|
|
||||||
|
def exists(p, l):
|
||||||
|
for l1 in l:
|
||||||
|
if p(l1):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def forall(p, l):
|
||||||
|
for l1 in l:
|
||||||
|
if not p(l1):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def add_prefix(instrs):
|
||||||
|
# Add compatibility macros for all systems, plus hardware
|
||||||
|
# definitions and compatibility macros for iOS.
|
||||||
|
#
|
||||||
|
# All systems:
|
||||||
|
#
|
||||||
|
# Glo() cpp macro for making global symbols (xxx vs _xxx)
|
||||||
|
# Loc() cpp macro for making local symbols (.Lxxx vs Lxxx)
|
||||||
|
# .funtype Expands to .thumb_func for iOS armv7 (null for armv6)
|
||||||
|
# Expands to .type %function for others
|
||||||
|
#
|
||||||
|
# iOS:
|
||||||
|
#
|
||||||
|
# .machine armv6/armv7
|
||||||
|
# .thumb (for armv7)
|
||||||
|
# cbz Expands to cmp/beq for armv6 (Thumb-only instr)
|
||||||
|
# .type Not supported by Apple assembler
|
||||||
|
# .size Not supported by Apple assembler
|
||||||
|
#
|
||||||
|
defre = '#[ \t]*if.*def.*SYS' # Add new defs near first existing ones
|
||||||
|
skipre = '$|\.syntax[ \t]' # Skip comment lines (and .syntax)
|
||||||
|
|
||||||
|
for i in range(len(instrs)):
|
||||||
|
if re.match(defre, instrs[i][1]):
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
i = 0
|
||||||
|
for i in range(i, len(instrs)):
|
||||||
|
if not re.match(skipre, instrs[i][1]):
|
||||||
|
break
|
||||||
|
instrs[i:0] = [
|
||||||
|
('', '', '\n'),
|
||||||
|
('/* Apple compatibility macros */', '', '\n'),
|
||||||
|
('', '#if defined(SYS_macosx)', '\n'),
|
||||||
|
('', '#define Glo(s) _##s', '\n'),
|
||||||
|
('', '#define Loc(s) L##s', '\n'),
|
||||||
|
('', '#if defined(MODEL_armv6)', '\n'),
|
||||||
|
(' ', '.machine armv6', '\n'),
|
||||||
|
(' ', '.macro .funtype', '\n'),
|
||||||
|
(' ', '.endm', '\n'),
|
||||||
|
(' ', '.macro cbz', '\n'),
|
||||||
|
(' ', 'cmp $0, #0', '\n'),
|
||||||
|
(' ', 'beq $1', '\n'),
|
||||||
|
(' ', '.endm', '\n'),
|
||||||
|
('', '#else', '\n'),
|
||||||
|
(' ', '.machine armv7', '\n'),
|
||||||
|
('', '#if !defined(NO_THUMB)', '\n'),
|
||||||
|
(' ', '.thumb', '\n'),
|
||||||
|
('', '#endif', '\n'),
|
||||||
|
(' ', '.macro .funtype', '\n'),
|
||||||
|
('', '#if !defined(NO_THUMB)', '\n'),
|
||||||
|
(' ', '.thumb_func $0', '\n'),
|
||||||
|
('', '#endif', '\n'),
|
||||||
|
(' ', '.endm', '\n'),
|
||||||
|
('', '#endif', '\n'),
|
||||||
|
(' ', '.macro .type', '\n'),
|
||||||
|
(' ', '.endm', '\n'),
|
||||||
|
(' ', '.macro .size', '\n'),
|
||||||
|
(' ', '.endm', '\n'),
|
||||||
|
(' ', '.macro .skip', '\n'),
|
||||||
|
(' ', '.space $0', '\n'),
|
||||||
|
(' ', '.endm', '\n'),
|
||||||
|
(' ', '.macro .fpu', '\n'),
|
||||||
|
(' ', '.endm', '\n'),
|
||||||
|
(' ', '.macro .global', '\n'),
|
||||||
|
(' ', '.globl $0', '\n'),
|
||||||
|
(' ', '.endm', '\n'),
|
||||||
|
('', '#else', '\n'),
|
||||||
|
('', '#define Glo(s) s', '\n'),
|
||||||
|
('', '#define Loc(s) .L##s', '\n'),
|
||||||
|
(' ', '.macro .funtype symbol', '\n'),
|
||||||
|
(' ', '.type \\symbol, %function', '\n'),
|
||||||
|
(' ', '.endm', '\n'),
|
||||||
|
('', '#endif', '\n'),
|
||||||
|
('/* End Apple compatibility macros */', '', '\n'),
|
||||||
|
('', '', '\n')
|
||||||
|
]
|
||||||
|
return instrs
|
||||||
|
|
||||||
|
|
||||||
|
# Regular expression for modified ldr lines
|
||||||
|
#
|
||||||
|
g_ldre = '(ldr[ \t][^,]*,[ \t]*)=(([^ \t\n@,/]|/(?!\*))*)(.*)'
|
||||||
|
|
||||||
|
|
||||||
|
def explicit_address_loads(instrs):
|
||||||
|
# Linux assemblers allow the following:
|
||||||
|
#
|
||||||
|
# ldr rM, =symbol
|
||||||
|
#
|
||||||
|
# which loads rM with [mov] (immediately) if possible, or creates an
|
||||||
|
# entry in memory for the symbol value and loads it PC-relatively
|
||||||
|
# with [ldr].
|
||||||
|
#
|
||||||
|
# The Apple assembler doesn't seem to support this notation. If the
|
||||||
|
# value is a suitable constant, it emits a valid [mov]. Otherwise
|
||||||
|
# it seems to emit an invalid [ldr] that always generates an error.
|
||||||
|
# (At least I have not been able to make it work). So, change uses
|
||||||
|
# of =symbol to explicit PC-relative loads.
|
||||||
|
#
|
||||||
|
# This requires a pool containing the addresses to be loaded. For
|
||||||
|
# now, we just keep track of it ourselves and emit it into the text
|
||||||
|
# segment at the end of the file.
|
||||||
|
#
|
||||||
|
syms = {}
|
||||||
|
result = []
|
||||||
|
|
||||||
|
def repl1((syms, result), (a, b, c)):
|
||||||
|
global g_poolpfx
|
||||||
|
global g_ldre
|
||||||
|
(b1, b2, b3) = parse_iparts(b)
|
||||||
|
mo = re.match(g_ldre, b3, re.DOTALL)
|
||||||
|
if mo:
|
||||||
|
if mo.group(2) not in syms:
|
||||||
|
syms[mo.group(2)] = len(syms)
|
||||||
|
psym = mo.group(2)
|
||||||
|
if psym[0:2] == '.L':
|
||||||
|
psym = psym[2:]
|
||||||
|
newb3 = mo.group(1) + g_poolpfx + psym + mo.group(4)
|
||||||
|
result.append((a, b1 + b2 + newb3, c))
|
||||||
|
else:
|
||||||
|
result.append((a, b, c))
|
||||||
|
return (syms, result)
|
||||||
|
|
||||||
|
def pool1(result, s):
|
||||||
|
global g_poolpfx
|
||||||
|
psym = s
|
||||||
|
if psym[0:2] == '.L':
|
||||||
|
psym = psym[2:]
|
||||||
|
result.append(('', g_poolpfx + psym + ':', '\n'))
|
||||||
|
result.append((' ', '.long ' + s, '\n'))
|
||||||
|
return result
|
||||||
|
|
||||||
|
reduce(repl1, instrs, (syms, result))
|
||||||
|
if len(syms) > 0:
|
||||||
|
result.append(('', '', '\n'))
|
||||||
|
result.append(('/* Pool of addresses loaded into registers */',
|
||||||
|
'', '\n'))
|
||||||
|
result.append(('', '', '\n'))
|
||||||
|
result.append((' ', '.text', '\n'))
|
||||||
|
result.append((' ', '.align 2', '\n'))
|
||||||
|
reduce(pool1, sorted(syms, key=syms.get), result)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def global_symbols(instrs):
|
||||||
|
# The form of a global symbol differs between Linux assemblers and
|
||||||
|
# the Apple assember:
|
||||||
|
#
|
||||||
|
# Linux: xxx
|
||||||
|
# Apple: _xxx
|
||||||
|
#
|
||||||
|
# Change occurrences of global symbols to use the Glo() cpp macro
|
||||||
|
# defined in our prefix.
|
||||||
|
#
|
||||||
|
# We consider a symbol to be global if:
|
||||||
|
#
|
||||||
|
# a. It appears in a .globl declaration; or
|
||||||
|
# b. It is referenced, has global form, and is not defined
|
||||||
|
#
|
||||||
|
glosyms = set(initial_glosyms)
|
||||||
|
refsyms = set()
|
||||||
|
defsyms = set(initial_defsyms)
|
||||||
|
result = []
|
||||||
|
|
||||||
|
def findglo1 (glosyms, (a, b, c)):
|
||||||
|
if re.match('#', b):
|
||||||
|
# Preprocessor line; nothing to do
|
||||||
|
return glosyms
|
||||||
|
(b1, b2, b3) = parse_iparts(b)
|
||||||
|
mo = re.match('(\.globa?l)' + ccce(g_ccid), b3)
|
||||||
|
if mo:
|
||||||
|
tokens = parse_expr(b3[len(mo.group(1)):])
|
||||||
|
if forall(lambda t: token_type(t) in ['space', 'id', ','], tokens):
|
||||||
|
for t in tokens:
|
||||||
|
if token_type(t) == 'id':
|
||||||
|
glosyms.add(t)
|
||||||
|
return glosyms
|
||||||
|
|
||||||
|
def findref1 ((refsyms, skipct), (a, b, c)):
|
||||||
|
|
||||||
|
def looksglobal(s):
|
||||||
|
if re.match('(r|a|v|p|c|cr|f|s|d|q|mvax|wcgr)[0-9]+$', s, re.I):
|
||||||
|
return False # numbered registers
|
||||||
|
if re.match('(wr|sb|sl|fp|ip|sp|lr|pc)$', s, re.I):
|
||||||
|
return False # named registers
|
||||||
|
if re.match('(fpsid|fpscr|fpexc|mvfr1|mvfr0)$', s, re.I):
|
||||||
|
return False # more named registers
|
||||||
|
if re.match('(mvf|mvd|mvfx|mvdx|dspsc)$', s, re.I):
|
||||||
|
return False # even more named registers
|
||||||
|
if re.match('(wcid|wcon|wcssf|wcasf|acc)$', s, re.I):
|
||||||
|
return False # even more named registers
|
||||||
|
if re.match('\.$|\.L|[0-9]|#', s):
|
||||||
|
return False # dot, local symbol, or number
|
||||||
|
if re.match('(asl|lsl|lsr|asr|ror|rrx)$', s, re.I):
|
||||||
|
return False # shift names
|
||||||
|
return True
|
||||||
|
|
||||||
|
if re.match('#', b):
|
||||||
|
# Preprocessor line; nothing to do
|
||||||
|
return (refsyms, skipct)
|
||||||
|
|
||||||
|
# Track nesting of .macro/.endm. For now, we don't look for
|
||||||
|
# global syms in macro defs. (Avoiding scoping probs etc.)
|
||||||
|
#
|
||||||
|
if skipct > 0 and re.match('\.(endm|endmacro)' + ccce(g_ccid), b):
|
||||||
|
return (refsyms, skipct - 1)
|
||||||
|
if re.match('\.macro' + ccce(g_ccid), b):
|
||||||
|
return (refsyms, skipct + 1)
|
||||||
|
if skipct > 0:
|
||||||
|
return (refsyms, skipct)
|
||||||
|
if re.match('\.(type|size|syntax|arch|fpu)' + ccce(g_ccid), b):
|
||||||
|
return (refsyms, skipct)
|
||||||
|
|
||||||
|
(b1, b2, b3) = parse_iparts(b)
|
||||||
|
rtokens = parse_rexpr(b3)
|
||||||
|
if len(rtokens) > 1 and rtokens[1] == '.req':
|
||||||
|
# .req has atypical syntax; no symbol refs there anyway
|
||||||
|
return (refsyms, skipct)
|
||||||
|
for t in rtokens[1:]:
|
||||||
|
if token_type(t) == 'id' and looksglobal(t):
|
||||||
|
refsyms.add(t)
|
||||||
|
return (refsyms, skipct)
|
||||||
|
|
||||||
|
def finddef1(defsyms, (a, b, c)):
|
||||||
|
if re.match('#', b):
|
||||||
|
# Preprocessor line
|
||||||
|
return defsyms
|
||||||
|
(b1, b2, b3) = parse_iparts(b)
|
||||||
|
rtokens = parse_rexpr(b3)
|
||||||
|
if b1 != '':
|
||||||
|
defsyms.add(b1)
|
||||||
|
if len(rtokens) > 1 and rtokens[1] == '.req':
|
||||||
|
defsyms.add(rtokens[0])
|
||||||
|
return defsyms
|
||||||
|
|
||||||
|
def repl1((glosyms, result), (a, b, c)):
|
||||||
|
if re.match('#', b):
|
||||||
|
# Preprocessor line
|
||||||
|
result.append((a, b, c))
|
||||||
|
return (glosyms, result)
|
||||||
|
toglo = lambda s: 'Glo(' + s + ')'
|
||||||
|
(b1, b2, b3) = parse_iparts(b)
|
||||||
|
tokens = parse_expr(b3)
|
||||||
|
|
||||||
|
if b1 in glosyms:
|
||||||
|
b1 = toglo(b1)
|
||||||
|
for i in range(len(tokens)):
|
||||||
|
if token_type(tokens[i]) == 'id' and tokens[i] in glosyms:
|
||||||
|
tokens[i] = toglo(tokens[i])
|
||||||
|
result.append((a, b1 + b2 + ''.join(tokens), c))
|
||||||
|
return (glosyms, result)
|
||||||
|
|
||||||
|
reduce(findglo1, instrs, glosyms)
|
||||||
|
reduce(findref1, instrs, (refsyms, 0))
|
||||||
|
reduce(finddef1, instrs, defsyms)
|
||||||
|
glosyms |= (refsyms - defsyms)
|
||||||
|
reduce(repl1, instrs, (glosyms, result))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def local_symbols(instrs):
|
||||||
|
# The form of a local symbol differs between Linux assemblers and
|
||||||
|
# the Apple assember:
|
||||||
|
#
|
||||||
|
# Linux: .Lxxx
|
||||||
|
# Apple: Lxxx
|
||||||
|
#
|
||||||
|
# Change occurrences of local symbols to use the Loc() cpp macro
|
||||||
|
# defined in our prefix.
|
||||||
|
#
|
||||||
|
lsyms = set()
|
||||||
|
result = []
|
||||||
|
|
||||||
|
def find1 (lsyms, (a, b, c)):
|
||||||
|
mo = re.match('(\.L[^ \t:]*)[ \t]*:', b)
|
||||||
|
if mo:
|
||||||
|
lsyms.add(mo.group(1))
|
||||||
|
return lsyms
|
||||||
|
|
||||||
|
def repl1((lsyms, result), (a, b, c)):
|
||||||
|
matches = list(re.finditer('\.L[^ \t@:,+*/\-()]+', b))
|
||||||
|
if matches != []:
|
||||||
|
matches.reverse()
|
||||||
|
newb = b
|
||||||
|
for mo in matches:
|
||||||
|
if mo.group() in lsyms:
|
||||||
|
newb = newb[0:mo.start()] + \
|
||||||
|
'Loc(' + mo.group()[2:] + ')' + \
|
||||||
|
newb[mo.end():]
|
||||||
|
result.append((a, newb, c))
|
||||||
|
else:
|
||||||
|
result.append((a, b, c))
|
||||||
|
return (lsyms, result)
|
||||||
|
|
||||||
|
reduce(find1, instrs, lsyms)
|
||||||
|
reduce(repl1, instrs, (lsyms, result))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def funtypes(instrs):
|
||||||
|
# Linux assemblers accept declarations like this:
|
||||||
|
#
|
||||||
|
# .type symbol, %function
|
||||||
|
#
|
||||||
|
# For Thumb functions, the Apple assembler wants to see:
|
||||||
|
#
|
||||||
|
# .thumb_func symbol
|
||||||
|
#
|
||||||
|
# Handle this by converting declarations to this:
|
||||||
|
#
|
||||||
|
# .funtype symbol
|
||||||
|
#
|
||||||
|
# Our prefix defines an appropriate .funtype macro for each
|
||||||
|
# environment.
|
||||||
|
#
|
||||||
|
result = []
|
||||||
|
|
||||||
|
def repl1(result, (a, b, c)):
|
||||||
|
mo = re.match('.type[ \t]+([^ \t,]*),[ \t]*%function', b)
|
||||||
|
if mo:
|
||||||
|
result.append((a, '.funtype ' + mo.group(1), c))
|
||||||
|
else:
|
||||||
|
result.append((a, b, c))
|
||||||
|
return result
|
||||||
|
|
||||||
|
reduce(repl1, instrs, result)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def jump_tables(instrs):
|
||||||
|
# Jump tables for Linux assemblers often look like this:
|
||||||
|
#
|
||||||
|
# tbh [pc, rM, lsl #1]
|
||||||
|
# .short (.Labc-.)/2+0
|
||||||
|
# .short (.Ldef-.)/2+1
|
||||||
|
# .short (.Lghi-.)/2+2
|
||||||
|
#
|
||||||
|
# The Apple assembler disagrees about the meaning of this code,
|
||||||
|
# producing jump tables that don't work. Convert to the following:
|
||||||
|
#
|
||||||
|
# tbh [pc, rM, lsl #1]
|
||||||
|
# .LBxxx:
|
||||||
|
# .short (.Labc-.LBxxx)/2
|
||||||
|
# .short (.Ldef-.LBxxx)/2
|
||||||
|
# .short (.Lghi-.LBxxx)/2
|
||||||
|
#
|
||||||
|
# In fact we just convert sequences of .short pseudo-ops of the
|
||||||
|
# right form. There's no requirement that they follow a tbh
|
||||||
|
# instruction.
|
||||||
|
#
|
||||||
|
baselabs = []
|
||||||
|
result = []
|
||||||
|
|
||||||
|
def short_match(seq, op):
|
||||||
|
# Determine whether the op is a .short of the form that needs to
|
||||||
|
# be converted: .short (symbol-.)/2+k. If so, return a pair
|
||||||
|
# containing the symbol and the value of k. If not, return
|
||||||
|
# None. The short can only be converted if there were at least
|
||||||
|
# k other .shorts in sequence before the current one. A summary
|
||||||
|
# of the previous .shorts is in seq.
|
||||||
|
#
|
||||||
|
# (A real parser would do a better job, but this was quick to
|
||||||
|
# get working.)
|
||||||
|
#
|
||||||
|
sp = '([ \t]|/\*.*?\*/)*' # space
|
||||||
|
sp1 = '([ \t]|/\*.*?\*/)+' # at least 1 space
|
||||||
|
spe = '([ \t]|/\*.*?\*/|@[^\n]*)*$' # end-of-instr space
|
||||||
|
expr_re0 = (
|
||||||
|
'\.short' + sp + '\(' + sp + # .short (
|
||||||
|
'([^ \t+\-*/@()]+)' + sp + # symbol
|
||||||
|
'-' + sp + '\.' + sp + '\)' + sp + # -.)
|
||||||
|
'/' + sp + '2' + spe # /2 END
|
||||||
|
)
|
||||||
|
expr_re1 = (
|
||||||
|
'\.short' + sp + '\(' + sp + # .short (
|
||||||
|
'([^ \t+\-*/@()]+)' + sp + # symbol
|
||||||
|
'-' + sp + '\.' + sp + '\)' + sp + # -.)
|
||||||
|
'/' + sp + '2' + sp + # /2
|
||||||
|
'\+' + sp + # +
|
||||||
|
'((0[xX])?[0-9]+)' + spe # k END
|
||||||
|
)
|
||||||
|
expr_re2 = (
|
||||||
|
'\.short' + sp1 + # .short
|
||||||
|
'((0[xX])?[0-9]+)' + sp + # k
|
||||||
|
'\+' + sp + '\(' + sp + # +(
|
||||||
|
'([^ \t+\-*/@()]+)' + sp + # symbol
|
||||||
|
'-' + sp + '\.' + sp + '\)' + sp + # -.)
|
||||||
|
'/' + sp + '2' + spe # /2 END
|
||||||
|
)
|
||||||
|
mo = re.match(expr_re0, op)
|
||||||
|
if mo:
|
||||||
|
return(mo.group(3), 0)
|
||||||
|
mo = re.match(expr_re1, op)
|
||||||
|
if mo:
|
||||||
|
k = int(mo.group(11), 0)
|
||||||
|
if k > len(seq):
|
||||||
|
return None
|
||||||
|
return (mo.group(3), k)
|
||||||
|
mo = re.match(expr_re2, op)
|
||||||
|
if mo:
|
||||||
|
k = int(mo.group(2), 0)
|
||||||
|
if k > len(seq):
|
||||||
|
return None
|
||||||
|
return (mo.group(7), k)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def conv1 ((baselabs, shortseq, label, result), (a, b, c)):
|
||||||
|
# Convert current instr (a,b,c) if it's a .short of the right
|
||||||
|
# form that spans a previous sequence of .shorts.
|
||||||
|
#
|
||||||
|
(b1, b2, b3) = parse_iparts(b)
|
||||||
|
|
||||||
|
if b3 == '':
|
||||||
|
# No operation: just note label if present.
|
||||||
|
result.append((a, b, c))
|
||||||
|
if re.match('\.L.', b1):
|
||||||
|
return (baselabs, shortseq, b1, result)
|
||||||
|
return (baselabs, shortseq, label, result)
|
||||||
|
|
||||||
|
if not re.match('.short[ \t]+[^ \t@]', b3):
|
||||||
|
# Not a .short: clear shortseq and label
|
||||||
|
result.append((a, b, c))
|
||||||
|
return (baselabs, [], '', result)
|
||||||
|
|
||||||
|
# We have a .short: figure out the label if any
|
||||||
|
if re.match('\.L', b1):
|
||||||
|
sl = b1
|
||||||
|
else:
|
||||||
|
sl = label
|
||||||
|
|
||||||
|
mpair = short_match(shortseq, b3)
|
||||||
|
if not mpair:
|
||||||
|
# A .short, but not of right form
|
||||||
|
shortseq.append((len(result), sl))
|
||||||
|
result.append((a, b, c))
|
||||||
|
return (baselabs, shortseq, '', result)
|
||||||
|
|
||||||
|
# OK, we have a .short to convert!
|
||||||
|
(sym, k) = mpair
|
||||||
|
shortseq.append((len(result), sl))
|
||||||
|
|
||||||
|
# Figure out base label (create one if necessary).
|
||||||
|
bx = len(shortseq) - 1 - k
|
||||||
|
bl = shortseq[bx][1]
|
||||||
|
if bl == '':
|
||||||
|
bl = g_basepfx + str(shortseq[bx][0])
|
||||||
|
shortseq[bx] = (shortseq[bx][0], bl)
|
||||||
|
baselabs.append(shortseq[bx])
|
||||||
|
|
||||||
|
op = '.short\t(' + sym + '-' + bl + ')/2'
|
||||||
|
|
||||||
|
result.append ((a, b1 + b2 + op, c))
|
||||||
|
return (baselabs, shortseq, '', result)
|
||||||
|
|
||||||
|
# Convert, accumulate result and new labels.
|
||||||
|
reduce(conv1, instrs, (baselabs, [], '', result))
|
||||||
|
|
||||||
|
# Add labels created here to the instruction stream.
|
||||||
|
baselabs.reverse()
|
||||||
|
for (ix, lab) in baselabs:
|
||||||
|
result[ix:0] = [('', lab + ':', '\n')]
|
||||||
|
|
||||||
|
# That does it
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def dot_relative(instrs):
|
||||||
|
# The Apple assembler (or possibly the linker) has trouble with code
|
||||||
|
# that looks like this:
|
||||||
|
#
|
||||||
|
# .word .Label - . + 0x80000000
|
||||||
|
# .word 0x1966
|
||||||
|
# .Label:
|
||||||
|
# .word 0x1967
|
||||||
|
#
|
||||||
|
# One way to describe the problem is that the assembler marks the
|
||||||
|
# first .word for relocation when in fact it's an assembly-time
|
||||||
|
# constant. Translate to the following form, which doesn't generate
|
||||||
|
# a relocation marking:
|
||||||
|
#
|
||||||
|
# DR0 = .Label - . + 0x80000000
|
||||||
|
# .word DR0
|
||||||
|
# .word 0x1966
|
||||||
|
# .Label:
|
||||||
|
# .word 0x1967
|
||||||
|
#
|
||||||
|
prefix = 'DR'
|
||||||
|
pseudos = '(\.byte|\.short|\.word|\.long|\.quad)'
|
||||||
|
result = []
|
||||||
|
|
||||||
|
def tok_ok(t):
|
||||||
|
return t in ['.', '+', '-', '(', ')'] or \
|
||||||
|
token_type(t) in ['space', 'locid', 'number']
|
||||||
|
|
||||||
|
def dotrel_match(expr):
|
||||||
|
# Determine whether the expression is one that needs to be
|
||||||
|
# translated.
|
||||||
|
tokens = parse_expr(expr)
|
||||||
|
return forall(tok_ok, tokens) and \
|
||||||
|
exists(lambda t: token_type(t) == 'locid', tokens) and \
|
||||||
|
exists(lambda t: token_type(t) == 'number', tokens) and \
|
||||||
|
exists(lambda t: t == '-', tokens) and \
|
||||||
|
exists(lambda t: t == '.', tokens)
|
||||||
|
|
||||||
|
def conv1(result, (a, b, c)):
|
||||||
|
if re.match('#', b):
|
||||||
|
# Preprocessor line
|
||||||
|
result.append((a, b, c))
|
||||||
|
else:
|
||||||
|
(b1, b2, b3) = parse_iparts(b)
|
||||||
|
mo = re.match(pseudos + ccce(g_ccid), b3)
|
||||||
|
if mo:
|
||||||
|
p = mo.group(1)
|
||||||
|
expr = b3[len(p):]
|
||||||
|
if dotrel_match(expr):
|
||||||
|
sym = prefix + str(len(result))
|
||||||
|
instr = sym + ' =' + expr
|
||||||
|
result.append(('', instr, '\n'))
|
||||||
|
result.append((a, b1 + b2 + p + ' ' + sym, c))
|
||||||
|
else:
|
||||||
|
result.append((a, b, c))
|
||||||
|
else:
|
||||||
|
result.append((a, b, c))
|
||||||
|
return result
|
||||||
|
|
||||||
|
reduce(conv1, instrs, result)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def read_input():
|
||||||
|
# Concatenate all the input files into a string.
|
||||||
|
#
|
||||||
|
def fnl(s):
|
||||||
|
if s == '' or s[-1] == '\n':
|
||||||
|
return s
|
||||||
|
else:
|
||||||
|
return s + '\n'
|
||||||
|
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
return fnl(sys.stdin.read())
|
||||||
|
else:
|
||||||
|
input = ""
|
||||||
|
for f in sys.argv[1:]:
|
||||||
|
# allow global symbols to be enabled or disabled, eg:
|
||||||
|
# --global=foo,!bar
|
||||||
|
# foo is forced to be global
|
||||||
|
# bar is forced to be non-global
|
||||||
|
if f.startswith('--global='):
|
||||||
|
glist = f[9:].split(',')
|
||||||
|
for g in glist:
|
||||||
|
if g.startswith('!'):
|
||||||
|
initial_defsyms.append(g[1:])
|
||||||
|
else:
|
||||||
|
initial_glosyms.append(g)
|
||||||
|
elif f.startswith('--stdin'):
|
||||||
|
input = input + fnl(sys.stdin.read())
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
fd = open(f)
|
||||||
|
input = input + fnl(fd.read())
|
||||||
|
fd.close()
|
||||||
|
except:
|
||||||
|
sys.stderr.write('arm-as-to-ios: cannot open ' + f + '\n')
|
||||||
|
return input
|
||||||
|
|
||||||
|
|
||||||
|
def parse_instrs(s):
|
||||||
|
# Parse the string into assembly instructions, also noting C
|
||||||
|
# preprocessor lines. Each instruction is represented as a triple:
|
||||||
|
# (space/comments, instruction, end). The end is either ';' or
|
||||||
|
# '\n'.
|
||||||
|
#
|
||||||
|
def goodmo(mo):
|
||||||
|
if mo == None:
|
||||||
|
# Should never happen
|
||||||
|
sys.stderr.write('arm-as-to-ios: internal parsing error\n')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
cpp_re = '([ \t]*)(#([^\n]*\\\\\n)*[^\n]*[^\\\\\n])\n'
|
||||||
|
comment_re = '[ \t]*#[^\n]*'
|
||||||
|
instr_re = (
|
||||||
|
'(([ \t]|/\*.*?\*/|@[^\n]*)*)' # Spaces & comments
|
||||||
|
'(([ \t]|/\*.*?\*/|[^;\n])*)' # "Instruction"
|
||||||
|
'([;\n])' # End
|
||||||
|
)
|
||||||
|
instrs = []
|
||||||
|
while s != '':
|
||||||
|
if re.match('[ \t]*#[ \t]*(if|ifdef|elif|else|endif|define)', s):
|
||||||
|
mo = re.match(cpp_re, s)
|
||||||
|
goodmo(mo)
|
||||||
|
instrs.append((mo.group(1), mo.group(2), '\n'))
|
||||||
|
elif re.match('[ \t]*#', s):
|
||||||
|
mo = re.match(comment_re, s)
|
||||||
|
goodmo(mo)
|
||||||
|
instrs.append((mo.group(0), '', '\n'))
|
||||||
|
else:
|
||||||
|
mo = re.match(instr_re, s, re.DOTALL)
|
||||||
|
goodmo(mo)
|
||||||
|
instrs.append((mo.group(1), mo.group(3), mo.group(5)))
|
||||||
|
s = s[len(mo.group(0)):]
|
||||||
|
return instrs
|
||||||
|
|
||||||
|
|
||||||
|
def parse_iparts(i):
|
||||||
|
# Parse an instruction into smaller parts, returning a triple of
|
||||||
|
# strings (label, colon, operation). The colon part also contains
|
||||||
|
# any surrounding spaces and comments (making the label and the
|
||||||
|
# operation cleaner to process).
|
||||||
|
#
|
||||||
|
# (Caller warrants that the given string doesn't start with space or
|
||||||
|
# a comment. This is true for strings returned by the instruction
|
||||||
|
# parser.)
|
||||||
|
#
|
||||||
|
lab_re = (
|
||||||
|
'([^ \t:/@]+)' # Label
|
||||||
|
'(([ \t]|/\*.*?\*/|@[^\n]*)*)' # Spaces & comments
|
||||||
|
':' # Colon
|
||||||
|
'(([ \t]|/\*.*?\*/|@[^\n]*)*)' # Spaces & comments
|
||||||
|
'([^\n]*)' # Operation
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(i) > 0 and i[0] == '#':
|
||||||
|
# C preprocessor line; treat as operation.
|
||||||
|
return ('', '', i)
|
||||||
|
mo = re.match(lab_re, i)
|
||||||
|
if mo:
|
||||||
|
return (mo.group(1), mo.group(2) + ':' + mo.group(4), mo.group(6))
|
||||||
|
# No label, just an operation
|
||||||
|
return ('', '', i)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_expr(s):
|
||||||
|
# Parse a string into a sequence of tokens. A segment of white
|
||||||
|
# space (including comments) is treated as a token, so that the
|
||||||
|
# tokens can be reassembled into the string again.
|
||||||
|
#
|
||||||
|
result = []
|
||||||
|
while s != '':
|
||||||
|
mo = re.match('([ \t]|/\*.*?\*/|@.*)+', s)
|
||||||
|
if not mo:
|
||||||
|
# Glo(...) and Loc(...) are single tokens
|
||||||
|
mo = re.match('(Glo|Loc)\([^()]*\)', s)
|
||||||
|
if not mo:
|
||||||
|
mo = re.match('"([^\\\\"]|\\\\.)*"', s)
|
||||||
|
if not mo:
|
||||||
|
mo = re.match(g_ccid0 + g_ccid + '*', s)
|
||||||
|
if not mo:
|
||||||
|
mo = re.match('[0-9]+[bf]', s)
|
||||||
|
if not mo:
|
||||||
|
mo = re.match('0[Xx][0-9a-fA-F]+|[0-9]+', s)
|
||||||
|
if not mo:
|
||||||
|
mo = re.match('.', s)
|
||||||
|
result.append(mo.group(0))
|
||||||
|
s = s[len(mo.group(0)):]
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def parse_rexpr(s):
|
||||||
|
# Like parse_expr(), but return only "real" tokens, not the
|
||||||
|
# intervening space.
|
||||||
|
#
|
||||||
|
return filter(lambda t: token_type(t) != 'space', parse_expr(s))
|
||||||
|
|
||||||
|
|
||||||
|
def token_type(t):
|
||||||
|
# Determine the type of a token. Caller warrants that it was
|
||||||
|
# returned by parse_expr() or parse_rexpr().
|
||||||
|
#
|
||||||
|
if re.match('[ \t]|/\*|@', t):
|
||||||
|
return 'space'
|
||||||
|
if re.match('Glo\(', t):
|
||||||
|
return 'gloid'
|
||||||
|
if re.match('Loc\(', t):
|
||||||
|
return 'locid'
|
||||||
|
if re.match('"', t):
|
||||||
|
return 'string'
|
||||||
|
if re.match(g_ccid0, t):
|
||||||
|
return 'id'
|
||||||
|
if re.match('[0-9]+[bf]', t):
|
||||||
|
return 'label'
|
||||||
|
if re.match('[0-9]', t):
|
||||||
|
return 'number'
|
||||||
|
return t # Sui generis
|
||||||
|
|
||||||
|
|
||||||
|
def debug_parse(a, b, c):
|
||||||
|
# Show results of instuction stream parse.
|
||||||
|
#
|
||||||
|
(b1, b2, b3) = parse_iparts(b)
|
||||||
|
newb = '{' + b1 + '}' + '{' + b2 + '}' + '{' + b3 + '}'
|
||||||
|
sys.stdout.write('{' + a + '}' + newb + c)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
instrs = parse_instrs(read_input())
|
||||||
|
instrs = explicit_address_loads(instrs)
|
||||||
|
instrs = funtypes(instrs)
|
||||||
|
instrs = jump_tables(instrs)
|
||||||
|
instrs = global_symbols(instrs)
|
||||||
|
instrs = local_symbols(instrs)
|
||||||
|
instrs = dot_relative(instrs)
|
||||||
|
instrs = add_prefix(instrs)
|
||||||
|
for (a, b, c) in instrs:
|
||||||
|
sys.stdout.write(a + b + c)
|
||||||
|
|
||||||
|
|
||||||
|
main()
|
||||||
@@ -0,0 +1,730 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# arm-as-to-ios Modify ARM assembly code for the iOS assembler
|
||||||
|
#
|
||||||
|
# Copyright (c) 2012 Psellos http://psellos.com/
|
||||||
|
# Licensed under the MIT License:
|
||||||
|
# http://www.opensource.org/licenses/mit-license.php
|
||||||
|
#
|
||||||
|
# Resources for running OCaml on iOS: http://psellos.com/ocaml/
|
||||||
|
#
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
|
||||||
|
VERSION = '1.4.0'
|
||||||
|
|
||||||
|
# Character classes for expression lexing.
|
||||||
|
#
|
||||||
|
g_ccid0 = '[$.A-Z_a-z\x80-\xff]' # Beginning of id
|
||||||
|
g_ccid = '[$.0-9A-Z_a-z\x80-\xff]' # Later in id
|
||||||
|
def ccc(cc): # Complement the class
|
||||||
|
if cc[1] == '^':
|
||||||
|
return cc[0] + cc[2:]
|
||||||
|
return cc[0] + '^' + cc[1:]
|
||||||
|
def ccce(cc): # Complement the class, include EOL
|
||||||
|
return '(?:' + ccc(cc) + '|$)'
|
||||||
|
|
||||||
|
# Prefixes for pooled symbol labels and jump table base labels. They're
|
||||||
|
# in the space of Linux assembler local symbols. Later rules will
|
||||||
|
# modify them to the Loc() form.
|
||||||
|
#
|
||||||
|
g_poolpfx = '.LP'
|
||||||
|
g_basepfx = '.LB'
|
||||||
|
|
||||||
|
|
||||||
|
def exists(p, l):
|
||||||
|
for l1 in l:
|
||||||
|
if p(l1):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def forall(p, l):
|
||||||
|
for l1 in l:
|
||||||
|
if not p(l1):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def add_prefix(instrs):
|
||||||
|
# Add compatibility macros for all systems, plus hardware
|
||||||
|
# definitions and compatibility macros for iOS.
|
||||||
|
#
|
||||||
|
# All systems:
|
||||||
|
#
|
||||||
|
# Glo() cpp macro for making global symbols (xxx vs _xxx)
|
||||||
|
# Loc() cpp macro for making local symbols (.Lxxx vs Lxxx)
|
||||||
|
# .funtype Expands to .thumb_func for iOS armv7 (null for armv6)
|
||||||
|
# Expands to .type %function for others
|
||||||
|
#
|
||||||
|
# iOS:
|
||||||
|
#
|
||||||
|
# .machine armv6/armv7
|
||||||
|
# .thumb (for armv7)
|
||||||
|
# cbz Expands to cmp/beq for armv6 (Thumb-only instr)
|
||||||
|
# .type Not supported by Apple assembler
|
||||||
|
# .size Not supported by Apple assembler
|
||||||
|
#
|
||||||
|
defre = '#[ \t]*if.*def.*SYS' # Add new defs near first existing ones
|
||||||
|
skipre = '$|\.syntax[ \t]' # Skip comment lines (and .syntax)
|
||||||
|
|
||||||
|
for i in range(len(instrs)):
|
||||||
|
if re.match(defre, instrs[i][1]):
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
i = 0
|
||||||
|
for i in range(i, len(instrs)):
|
||||||
|
if not re.match(skipre, instrs[i][1]):
|
||||||
|
break
|
||||||
|
instrs[i:0] = [
|
||||||
|
('', '', '\n'),
|
||||||
|
('/* Apple compatibility macros */', '', '\n'),
|
||||||
|
('', '#if defined(SYS_macosx)', '\n'),
|
||||||
|
('', '#define Glo(s) _##s', '\n'),
|
||||||
|
('', '#define Loc(s) L##s', '\n'),
|
||||||
|
('', '#if defined(MODEL_armv6)', '\n'),
|
||||||
|
(' ', '.machine armv6', '\n'),
|
||||||
|
(' ', '.macro .funtype', '\n'),
|
||||||
|
(' ', '.endm', '\n'),
|
||||||
|
(' ', '.macro cbz', '\n'),
|
||||||
|
(' ', 'cmp $0, #0', '\n'),
|
||||||
|
(' ', 'beq $1', '\n'),
|
||||||
|
(' ', '.endm', '\n'),
|
||||||
|
('', '#else', '\n'),
|
||||||
|
(' ', '.machine armv7', '\n'),
|
||||||
|
(' ', '.thumb', '\n'),
|
||||||
|
(' ', '.macro .funtype', '\n'),
|
||||||
|
(' ', '.thumb_func $0', '\n'),
|
||||||
|
(' ', '.endm', '\n'),
|
||||||
|
('', '#endif', '\n'),
|
||||||
|
(' ', '.macro .type', '\n'),
|
||||||
|
(' ', '.endm', '\n'),
|
||||||
|
(' ', '.macro .size', '\n'),
|
||||||
|
(' ', '.endm', '\n'),
|
||||||
|
('', '#else', '\n'),
|
||||||
|
('', '#define Glo(s) s', '\n'),
|
||||||
|
('', '#define Loc(s) .L##s', '\n'),
|
||||||
|
(' ', '.macro .funtype symbol', '\n'),
|
||||||
|
(' ', '.type \\symbol, %function', '\n'),
|
||||||
|
(' ', '.endm', '\n'),
|
||||||
|
('', '#endif', '\n'),
|
||||||
|
('/* End Apple compatibility macros */', '', '\n'),
|
||||||
|
('', '', '\n')
|
||||||
|
]
|
||||||
|
return instrs
|
||||||
|
|
||||||
|
|
||||||
|
# Regular expression for modified ldr lines
|
||||||
|
#
|
||||||
|
g_ldre = '(ldr[ \t][^,]*,[ \t]*)=(([^ \t\n@,/]|/(?!\*))*)(.*)'
|
||||||
|
|
||||||
|
|
||||||
|
def explicit_address_loads(instrs):
|
||||||
|
# Linux assemblers allow the following:
|
||||||
|
#
|
||||||
|
# ldr rM, =symbol
|
||||||
|
#
|
||||||
|
# which loads rM with [mov] (immediately) if possible, or creates an
|
||||||
|
# entry in memory for the symbol value and loads it PC-relatively
|
||||||
|
# with [ldr].
|
||||||
|
#
|
||||||
|
# The Apple assembler doesn't seem to support this notation. If the
|
||||||
|
# value is a suitable constant, it emits a valid [mov]. Otherwise
|
||||||
|
# it seems to emit an invalid [ldr] that always generates an error.
|
||||||
|
# (At least I have not been able to make it work). So, change uses
|
||||||
|
# of =symbol to explicit PC-relative loads.
|
||||||
|
#
|
||||||
|
# This requires a pool containing the addresses to be loaded. For
|
||||||
|
# now, we just keep track of it ourselves and emit it into the text
|
||||||
|
# segment at the end of the file.
|
||||||
|
#
|
||||||
|
syms = {}
|
||||||
|
result = []
|
||||||
|
|
||||||
|
def repl1((syms, result), (a, b, c)):
|
||||||
|
global g_poolpfx
|
||||||
|
global g_ldre
|
||||||
|
(b1, b2, b3) = parse_iparts(b)
|
||||||
|
mo = re.match(g_ldre, b3, re.DOTALL)
|
||||||
|
if mo:
|
||||||
|
if mo.group(2) not in syms:
|
||||||
|
syms[mo.group(2)] = len(syms)
|
||||||
|
psym = mo.group(2)
|
||||||
|
if psym[0:2] == '.L':
|
||||||
|
psym = psym[2:]
|
||||||
|
newb3 = mo.group(1) + g_poolpfx + psym + mo.group(4)
|
||||||
|
result.append((a, b1 + b2 + newb3, c))
|
||||||
|
else:
|
||||||
|
result.append((a, b, c))
|
||||||
|
return (syms, result)
|
||||||
|
|
||||||
|
def pool1(result, s):
|
||||||
|
global g_poolpfx
|
||||||
|
psym = s
|
||||||
|
if psym[0:2] == '.L':
|
||||||
|
psym = psym[2:]
|
||||||
|
result.append(('', g_poolpfx + psym + ':', '\n'))
|
||||||
|
result.append((' ', '.long ' + s, '\n'))
|
||||||
|
return result
|
||||||
|
|
||||||
|
reduce(repl1, instrs, (syms, result))
|
||||||
|
if len(syms) > 0:
|
||||||
|
result.append(('', '', '\n'))
|
||||||
|
result.append(('/* Pool of addresses loaded into registers */',
|
||||||
|
'', '\n'))
|
||||||
|
result.append(('', '', '\n'))
|
||||||
|
result.append((' ', '.text', '\n'))
|
||||||
|
result.append((' ', '.align 2', '\n'))
|
||||||
|
reduce(pool1, sorted(syms, key=syms.get), result)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def global_symbols(instrs):
|
||||||
|
# The form of a global symbol differs between Linux assemblers and
|
||||||
|
# the Apple assember:
|
||||||
|
#
|
||||||
|
# Linux: xxx
|
||||||
|
# Apple: _xxx
|
||||||
|
#
|
||||||
|
# Change occurrences of global symbols to use the Glo() cpp macro
|
||||||
|
# defined in our prefix.
|
||||||
|
#
|
||||||
|
# We consider a symbol to be global if:
|
||||||
|
#
|
||||||
|
# a. It appears in a .globl declaration; or
|
||||||
|
# b. It is referenced, has global form, and is not defined
|
||||||
|
#
|
||||||
|
glosyms = set()
|
||||||
|
refsyms = set()
|
||||||
|
defsyms = set()
|
||||||
|
result = []
|
||||||
|
|
||||||
|
def findglo1 (glosyms, (a, b, c)):
|
||||||
|
if re.match('#', b):
|
||||||
|
# Preprocessor line; nothing to do
|
||||||
|
return glosyms
|
||||||
|
(b1, b2, b3) = parse_iparts(b)
|
||||||
|
mo = re.match('(\.globl)' + ccce(g_ccid), b3)
|
||||||
|
if mo:
|
||||||
|
tokens = parse_expr(b3[len(mo.group(1)):])
|
||||||
|
if forall(lambda t: token_type(t) in ['space', 'id', ','], tokens):
|
||||||
|
for t in tokens:
|
||||||
|
if token_type(t) == 'id':
|
||||||
|
glosyms.add(t)
|
||||||
|
return glosyms
|
||||||
|
|
||||||
|
def findref1 ((refsyms, skipct), (a, b, c)):
|
||||||
|
|
||||||
|
def looksglobal(s):
|
||||||
|
if re.match('(r|a|v|p|c|cr|f|s|d|q|mvax|wcgr)[0-9]+$', s, re.I):
|
||||||
|
return False # numbered registers
|
||||||
|
if re.match('(wr|sb|sl|fp|ip|sp|lr|pc)$', s, re.I):
|
||||||
|
return False # named registers
|
||||||
|
if re.match('(fpsid|fpscr|fpexc|mvfr1|mvfr0)$', s, re.I):
|
||||||
|
return False # more named registers
|
||||||
|
if re.match('(mvf|mvd|mvfx|mvdx|dspsc)$', s, re.I):
|
||||||
|
return False # even more named registers
|
||||||
|
if re.match('(wcid|wcon|wcssf|wcasf|acc)$', s, re.I):
|
||||||
|
return False # even more named registers
|
||||||
|
if re.match('\.$|\.L|[0-9]|#', s):
|
||||||
|
return False # dot, local symbol, or number
|
||||||
|
if re.match('(asl|lsl|lsr|asr|ror|rrx)$', s, re.I):
|
||||||
|
return False # shift names
|
||||||
|
return True
|
||||||
|
|
||||||
|
if re.match('#', b):
|
||||||
|
# Preprocessor line; nothing to do
|
||||||
|
return (refsyms, skipct)
|
||||||
|
|
||||||
|
# Track nesting of .macro/.endm. For now, we don't look for
|
||||||
|
# global syms in macro defs. (Avoiding scoping probs etc.)
|
||||||
|
#
|
||||||
|
if skipct > 0 and re.match('\.(endm|endmacro)' + ccce(g_ccid), b):
|
||||||
|
return (refsyms, skipct - 1)
|
||||||
|
if re.match('\.macro' + ccce(g_ccid), b):
|
||||||
|
return (refsyms, skipct + 1)
|
||||||
|
if skipct > 0:
|
||||||
|
return (refsyms, skipct)
|
||||||
|
if re.match('\.(type|size|syntax|arch|fpu)' + ccce(g_ccid), b):
|
||||||
|
return (refsyms, skipct)
|
||||||
|
|
||||||
|
(b1, b2, b3) = parse_iparts(b)
|
||||||
|
rtokens = parse_rexpr(b3)
|
||||||
|
if len(rtokens) > 1 and rtokens[1] == '.req':
|
||||||
|
# .req has atypical syntax; no symbol refs there anyway
|
||||||
|
return (refsyms, skipct)
|
||||||
|
for t in rtokens[1:]:
|
||||||
|
if token_type(t) == 'id' and looksglobal(t):
|
||||||
|
refsyms.add(t)
|
||||||
|
return (refsyms, skipct)
|
||||||
|
|
||||||
|
def finddef1(defsyms, (a, b, c)):
|
||||||
|
if re.match('#', b):
|
||||||
|
# Preprocessor line
|
||||||
|
return defsyms
|
||||||
|
(b1, b2, b3) = parse_iparts(b)
|
||||||
|
rtokens = parse_rexpr(b3)
|
||||||
|
if b1 != '':
|
||||||
|
defsyms.add(b1)
|
||||||
|
if len(rtokens) > 1 and rtokens[1] == '.req':
|
||||||
|
defsyms.add(rtokens[0])
|
||||||
|
return defsyms
|
||||||
|
|
||||||
|
def repl1((glosyms, result), (a, b, c)):
|
||||||
|
if re.match('#', b):
|
||||||
|
# Preprocessor line
|
||||||
|
result.append((a, b, c))
|
||||||
|
return (glosyms, result)
|
||||||
|
toglo = lambda s: 'Glo(' + s + ')'
|
||||||
|
(b1, b2, b3) = parse_iparts(b)
|
||||||
|
tokens = parse_expr(b3)
|
||||||
|
|
||||||
|
if b1 in glosyms:
|
||||||
|
b1 = toglo(b1)
|
||||||
|
for i in range(len(tokens)):
|
||||||
|
if token_type(tokens[i]) == 'id' and tokens[i] in glosyms:
|
||||||
|
tokens[i] = toglo(tokens[i])
|
||||||
|
result.append((a, b1 + b2 + ''.join(tokens), c))
|
||||||
|
return (glosyms, result)
|
||||||
|
|
||||||
|
reduce(findglo1, instrs, glosyms)
|
||||||
|
reduce(findref1, instrs, (refsyms, 0))
|
||||||
|
reduce(finddef1, instrs, defsyms)
|
||||||
|
glosyms |= (refsyms - defsyms)
|
||||||
|
reduce(repl1, instrs, (glosyms, result))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def local_symbols(instrs):
|
||||||
|
# The form of a local symbol differs between Linux assemblers and
|
||||||
|
# the Apple assember:
|
||||||
|
#
|
||||||
|
# Linux: .Lxxx
|
||||||
|
# Apple: Lxxx
|
||||||
|
#
|
||||||
|
# Change occurrences of local symbols to use the Loc() cpp macro
|
||||||
|
# defined in our prefix.
|
||||||
|
#
|
||||||
|
lsyms = set()
|
||||||
|
result = []
|
||||||
|
|
||||||
|
def find1 (lsyms, (a, b, c)):
|
||||||
|
mo = re.match('(\.L[^ \t:]*)[ \t]*:', b)
|
||||||
|
if mo:
|
||||||
|
lsyms.add(mo.group(1))
|
||||||
|
return lsyms
|
||||||
|
|
||||||
|
def repl1((lsyms, result), (a, b, c)):
|
||||||
|
matches = list(re.finditer('\.L[^ \t@:,+*/\-()]+', b))
|
||||||
|
if matches != []:
|
||||||
|
matches.reverse()
|
||||||
|
newb = b
|
||||||
|
for mo in matches:
|
||||||
|
if mo.group() in lsyms:
|
||||||
|
newb = newb[0:mo.start()] + \
|
||||||
|
'Loc(' + mo.group()[2:] + ')' + \
|
||||||
|
newb[mo.end():]
|
||||||
|
result.append((a, newb, c))
|
||||||
|
else:
|
||||||
|
result.append((a, b, c))
|
||||||
|
return (lsyms, result)
|
||||||
|
|
||||||
|
reduce(find1, instrs, lsyms)
|
||||||
|
reduce(repl1, instrs, (lsyms, result))
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def funtypes(instrs):
|
||||||
|
# Linux assemblers accept declarations like this:
|
||||||
|
#
|
||||||
|
# .type symbol, %function
|
||||||
|
#
|
||||||
|
# For Thumb functions, the Apple assembler wants to see:
|
||||||
|
#
|
||||||
|
# .thumb_func symbol
|
||||||
|
#
|
||||||
|
# Handle this by converting declarations to this:
|
||||||
|
#
|
||||||
|
# .funtype symbol
|
||||||
|
#
|
||||||
|
# Our prefix defines an appropriate .funtype macro for each
|
||||||
|
# environment.
|
||||||
|
#
|
||||||
|
result = []
|
||||||
|
|
||||||
|
def repl1(result, (a, b, c)):
|
||||||
|
mo = re.match('.type[ \t]+([^ \t,]*),[ \t]*%function', b)
|
||||||
|
if mo:
|
||||||
|
result.append((a, '.funtype ' + mo.group(1), c))
|
||||||
|
else:
|
||||||
|
result.append((a, b, c))
|
||||||
|
return result
|
||||||
|
|
||||||
|
reduce(repl1, instrs, result)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def jump_tables(instrs):
|
||||||
|
# Jump tables for Linux assemblers often look like this:
|
||||||
|
#
|
||||||
|
# tbh [pc, rM, lsl #1]
|
||||||
|
# .short (.Labc-.)/2+0
|
||||||
|
# .short (.Ldef-.)/2+1
|
||||||
|
# .short (.Lghi-.)/2+2
|
||||||
|
#
|
||||||
|
# The Apple assembler disagrees about the meaning of this code,
|
||||||
|
# producing jump tables that don't work. Convert to the following:
|
||||||
|
#
|
||||||
|
# tbh [pc, rM, lsl #1]
|
||||||
|
# .LBxxx:
|
||||||
|
# .short (.Labc-.LBxxx)/2
|
||||||
|
# .short (.Ldef-.LBxxx)/2
|
||||||
|
# .short (.Lghi-.LBxxx)/2
|
||||||
|
#
|
||||||
|
# In fact we just convert sequences of .short pseudo-ops of the
|
||||||
|
# right form. There's no requirement that they follow a tbh
|
||||||
|
# instruction.
|
||||||
|
#
|
||||||
|
baselabs = []
|
||||||
|
result = []
|
||||||
|
|
||||||
|
def short_match(seq, op):
|
||||||
|
# Determine whether the op is a .short of the form that needs to
|
||||||
|
# be converted: .short (symbol-.)/2+k. If so, return a pair
|
||||||
|
# containing the symbol and the value of k. If not, return
|
||||||
|
# None. The short can only be converted if there were at least
|
||||||
|
# k other .shorts in sequence before the current one. A summary
|
||||||
|
# of the previous .shorts is in seq.
|
||||||
|
#
|
||||||
|
# (A real parser would do a better job, but this was quick to
|
||||||
|
# get working.)
|
||||||
|
#
|
||||||
|
sp = '([ \t]|/\*.*?\*/)*' # space
|
||||||
|
sp1 = '([ \t]|/\*.*?\*/)+' # at least 1 space
|
||||||
|
spe = '([ \t]|/\*.*?\*/|@[^\n]*)*$' # end-of-instr space
|
||||||
|
expr_re0 = (
|
||||||
|
'\.short' + sp + '\(' + sp + # .short (
|
||||||
|
'([^ \t+\-*/@()]+)' + sp + # symbol
|
||||||
|
'-' + sp + '\.' + sp + '\)' + sp + # -.)
|
||||||
|
'/' + sp + '2' + spe # /2 END
|
||||||
|
)
|
||||||
|
expr_re1 = (
|
||||||
|
'\.short' + sp + '\(' + sp + # .short (
|
||||||
|
'([^ \t+\-*/@()]+)' + sp + # symbol
|
||||||
|
'-' + sp + '\.' + sp + '\)' + sp + # -.)
|
||||||
|
'/' + sp + '2' + sp + # /2
|
||||||
|
'\+' + sp + # +
|
||||||
|
'((0[xX])?[0-9]+)' + spe # k END
|
||||||
|
)
|
||||||
|
expr_re2 = (
|
||||||
|
'\.short' + sp1 + # .short
|
||||||
|
'((0[xX])?[0-9]+)' + sp + # k
|
||||||
|
'\+' + sp + '\(' + sp + # +(
|
||||||
|
'([^ \t+\-*/@()]+)' + sp + # symbol
|
||||||
|
'-' + sp + '\.' + sp + '\)' + sp + # -.)
|
||||||
|
'/' + sp + '2' + spe # /2 END
|
||||||
|
)
|
||||||
|
mo = re.match(expr_re0, op)
|
||||||
|
if mo:
|
||||||
|
return(mo.group(3), 0)
|
||||||
|
mo = re.match(expr_re1, op)
|
||||||
|
if mo:
|
||||||
|
k = int(mo.group(11), 0)
|
||||||
|
if k > len(seq):
|
||||||
|
return None
|
||||||
|
return (mo.group(3), k)
|
||||||
|
mo = re.match(expr_re2, op)
|
||||||
|
if mo:
|
||||||
|
k = int(mo.group(2), 0)
|
||||||
|
if k > len(seq):
|
||||||
|
return None
|
||||||
|
return (mo.group(7), k)
|
||||||
|
return None
|
||||||
|
|
||||||
|
def conv1 ((baselabs, shortseq, label, result), (a, b, c)):
|
||||||
|
# Convert current instr (a,b,c) if it's a .short of the right
|
||||||
|
# form that spans a previous sequence of .shorts.
|
||||||
|
#
|
||||||
|
(b1, b2, b3) = parse_iparts(b)
|
||||||
|
|
||||||
|
if b3 == '':
|
||||||
|
# No operation: just note label if present.
|
||||||
|
result.append((a, b, c))
|
||||||
|
if re.match('\.L.', b1):
|
||||||
|
return (baselabs, shortseq, b1, result)
|
||||||
|
return (baselabs, shortseq, label, result)
|
||||||
|
|
||||||
|
if not re.match('.short[ \t]+[^ \t@]', b3):
|
||||||
|
# Not a .short: clear shortseq and label
|
||||||
|
result.append((a, b, c))
|
||||||
|
return (baselabs, [], '', result)
|
||||||
|
|
||||||
|
# We have a .short: figure out the label if any
|
||||||
|
if re.match('\.L', b1):
|
||||||
|
sl = b1
|
||||||
|
else:
|
||||||
|
sl = label
|
||||||
|
|
||||||
|
mpair = short_match(shortseq, b3)
|
||||||
|
if not mpair:
|
||||||
|
# A .short, but not of right form
|
||||||
|
shortseq.append((len(result), sl))
|
||||||
|
result.append((a, b, c))
|
||||||
|
return (baselabs, shortseq, '', result)
|
||||||
|
|
||||||
|
# OK, we have a .short to convert!
|
||||||
|
(sym, k) = mpair
|
||||||
|
shortseq.append((len(result), sl))
|
||||||
|
|
||||||
|
# Figure out base label (create one if necessary).
|
||||||
|
bx = len(shortseq) - 1 - k
|
||||||
|
bl = shortseq[bx][1]
|
||||||
|
if bl == '':
|
||||||
|
bl = g_basepfx + str(shortseq[bx][0])
|
||||||
|
shortseq[bx] = (shortseq[bx][0], bl)
|
||||||
|
baselabs.append(shortseq[bx])
|
||||||
|
|
||||||
|
op = '.short\t(' + sym + '-' + bl + ')/2'
|
||||||
|
|
||||||
|
result.append ((a, b1 + b2 + op, c))
|
||||||
|
return (baselabs, shortseq, '', result)
|
||||||
|
|
||||||
|
# Convert, accumulate result and new labels.
|
||||||
|
reduce(conv1, instrs, (baselabs, [], '', result))
|
||||||
|
|
||||||
|
# Add labels created here to the instruction stream.
|
||||||
|
baselabs.reverse()
|
||||||
|
for (ix, lab) in baselabs:
|
||||||
|
result[ix:0] = [('', lab + ':', '\n')]
|
||||||
|
|
||||||
|
# That does it
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def dot_relative(instrs):
|
||||||
|
# The Apple assembler (or possibly the linker) has trouble with code
|
||||||
|
# that looks like this:
|
||||||
|
#
|
||||||
|
# .word .Label - . + 0x80000000
|
||||||
|
# .word 0x1966
|
||||||
|
# .Label:
|
||||||
|
# .word 0x1967
|
||||||
|
#
|
||||||
|
# One way to describe the problem is that the assembler marks the
|
||||||
|
# first .word for relocation when in fact it's an assembly-time
|
||||||
|
# constant. Translate to the following form, which doesn't generate
|
||||||
|
# a relocation marking:
|
||||||
|
#
|
||||||
|
# DR0 = .Label - . + 0x80000000
|
||||||
|
# .word DR0
|
||||||
|
# .word 0x1966
|
||||||
|
# .Label:
|
||||||
|
# .word 0x1967
|
||||||
|
#
|
||||||
|
prefix = 'DR'
|
||||||
|
pseudos = '(\.byte|\.short|\.word|\.long|\.quad)'
|
||||||
|
result = []
|
||||||
|
|
||||||
|
def tok_ok(t):
|
||||||
|
return t in ['.', '+', '-', '(', ')'] or \
|
||||||
|
token_type(t) in ['space', 'locid', 'number']
|
||||||
|
|
||||||
|
def dotrel_match(expr):
|
||||||
|
# Determine whether the expression is one that needs to be
|
||||||
|
# translated.
|
||||||
|
tokens = parse_expr(expr)
|
||||||
|
return forall(tok_ok, tokens) and \
|
||||||
|
exists(lambda t: token_type(t) == 'locid', tokens) and \
|
||||||
|
exists(lambda t: token_type(t) == 'number', tokens) and \
|
||||||
|
exists(lambda t: t == '-', tokens) and \
|
||||||
|
exists(lambda t: t == '.', tokens)
|
||||||
|
|
||||||
|
def conv1(result, (a, b, c)):
|
||||||
|
if re.match('#', b):
|
||||||
|
# Preprocessor line
|
||||||
|
result.append((a, b, c))
|
||||||
|
else:
|
||||||
|
(b1, b2, b3) = parse_iparts(b)
|
||||||
|
mo = re.match(pseudos + ccce(g_ccid), b3)
|
||||||
|
if mo:
|
||||||
|
p = mo.group(1)
|
||||||
|
expr = b3[len(p):]
|
||||||
|
if dotrel_match(expr):
|
||||||
|
sym = prefix + str(len(result))
|
||||||
|
instr = sym + ' =' + expr
|
||||||
|
result.append(('', instr, '\n'))
|
||||||
|
result.append((a, b1 + b2 + p + ' ' + sym, c))
|
||||||
|
else:
|
||||||
|
result.append((a, b, c))
|
||||||
|
else:
|
||||||
|
result.append((a, b, c))
|
||||||
|
return result
|
||||||
|
|
||||||
|
reduce(conv1, instrs, result)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def read_input():
|
||||||
|
# Concatenate all the input files into a string.
|
||||||
|
#
|
||||||
|
def fnl(s):
|
||||||
|
if s == '' or s[-1] == '\n':
|
||||||
|
return s
|
||||||
|
else:
|
||||||
|
return s + '\n'
|
||||||
|
|
||||||
|
if len(sys.argv) < 2:
|
||||||
|
return fnl(sys.stdin.read())
|
||||||
|
else:
|
||||||
|
input = ""
|
||||||
|
for f in sys.argv[1:]:
|
||||||
|
try:
|
||||||
|
fd = open(f)
|
||||||
|
input = input + fnl(fd.read())
|
||||||
|
fd.close()
|
||||||
|
except:
|
||||||
|
sys.stderr.write('arm-as-to-ios: cannot open ' + f + '\n')
|
||||||
|
return input
|
||||||
|
|
||||||
|
|
||||||
|
def parse_instrs(s):
|
||||||
|
# Parse the string into assembly instructions, also noting C
|
||||||
|
# preprocessor lines. Each instruction is represented as a triple:
|
||||||
|
# (space/comments, instruction, end). The end is either ';' or
|
||||||
|
# '\n'.
|
||||||
|
#
|
||||||
|
def goodmo(mo):
|
||||||
|
if mo == None:
|
||||||
|
# Should never happen
|
||||||
|
sys.stderr.write('arm-as-to-ios: internal parsing error\n')
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
cpp_re = '([ \t]*)(#([^\n]*\\\\\n)*[^\n]*[^\\\\\n])\n'
|
||||||
|
comment_re = '[ \t]*#[^\n]*'
|
||||||
|
instr_re = (
|
||||||
|
'(([ \t]|/\*.*?\*/|@[^\n]*)*)' # Spaces & comments
|
||||||
|
'(([ \t]|/\*.*?\*/|[^;\n])*)' # "Instruction"
|
||||||
|
'([;\n])' # End
|
||||||
|
)
|
||||||
|
instrs = []
|
||||||
|
while s != '':
|
||||||
|
if re.match('[ \t]*#[ \t]*(if|ifdef|elif|else|endif|define)', s):
|
||||||
|
mo = re.match(cpp_re, s)
|
||||||
|
goodmo(mo)
|
||||||
|
instrs.append((mo.group(1), mo.group(2), '\n'))
|
||||||
|
elif re.match('[ \t]*#', s):
|
||||||
|
mo = re.match(comment_re, s)
|
||||||
|
goodmo(mo)
|
||||||
|
instrs.append((mo.group(0), '', '\n'))
|
||||||
|
else:
|
||||||
|
mo = re.match(instr_re, s, re.DOTALL)
|
||||||
|
goodmo(mo)
|
||||||
|
instrs.append((mo.group(1), mo.group(3), mo.group(5)))
|
||||||
|
s = s[len(mo.group(0)):]
|
||||||
|
return instrs
|
||||||
|
|
||||||
|
|
||||||
|
def parse_iparts(i):
|
||||||
|
# Parse an instruction into smaller parts, returning a triple of
|
||||||
|
# strings (label, colon, operation). The colon part also contains
|
||||||
|
# any surrounding spaces and comments (making the label and the
|
||||||
|
# operation cleaner to process).
|
||||||
|
#
|
||||||
|
# (Caller warrants that the given string doesn't start with space or
|
||||||
|
# a comment. This is true for strings returned by the instruction
|
||||||
|
# parser.)
|
||||||
|
#
|
||||||
|
lab_re = (
|
||||||
|
'([^ \t:/@]+)' # Label
|
||||||
|
'(([ \t]|/\*.*?\*/|@[^\n]*)*)' # Spaces & comments
|
||||||
|
':' # Colon
|
||||||
|
'(([ \t]|/\*.*?\*/|@[^\n]*)*)' # Spaces & comments
|
||||||
|
'([^\n]*)' # Operation
|
||||||
|
)
|
||||||
|
|
||||||
|
if len(i) > 0 and i[0] == '#':
|
||||||
|
# C preprocessor line; treat as operation.
|
||||||
|
return ('', '', i)
|
||||||
|
mo = re.match(lab_re, i)
|
||||||
|
if mo:
|
||||||
|
return (mo.group(1), mo.group(2) + ':' + mo.group(4), mo.group(6))
|
||||||
|
# No label, just an operation
|
||||||
|
return ('', '', i)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_expr(s):
|
||||||
|
# Parse a string into a sequence of tokens. A segment of white
|
||||||
|
# space (including comments) is treated as a token, so that the
|
||||||
|
# tokens can be reassembled into the string again.
|
||||||
|
#
|
||||||
|
result = []
|
||||||
|
while s != '':
|
||||||
|
mo = re.match('([ \t]|/\*.*?\*/|@.*)+', s)
|
||||||
|
if not mo:
|
||||||
|
# Glo(...) and Loc(...) are single tokens
|
||||||
|
mo = re.match('(Glo|Loc)\([^()]*\)', s)
|
||||||
|
if not mo:
|
||||||
|
mo = re.match('"([^\\\\"]|\\\\.)*"', s)
|
||||||
|
if not mo:
|
||||||
|
mo = re.match(g_ccid0 + g_ccid + '*', s)
|
||||||
|
if not mo:
|
||||||
|
mo = re.match('[0-9]+[bf]', s)
|
||||||
|
if not mo:
|
||||||
|
mo = re.match('0[Xx][0-9a-fA-F]+|[0-9]+', s)
|
||||||
|
if not mo:
|
||||||
|
mo = re.match('.', s)
|
||||||
|
result.append(mo.group(0))
|
||||||
|
s = s[len(mo.group(0)):]
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def parse_rexpr(s):
|
||||||
|
# Like parse_expr(), but return only "real" tokens, not the
|
||||||
|
# intervening space.
|
||||||
|
#
|
||||||
|
return filter(lambda t: token_type(t) != 'space', parse_expr(s))
|
||||||
|
|
||||||
|
|
||||||
|
def token_type(t):
|
||||||
|
# Determine the type of a token. Caller warrants that it was
|
||||||
|
# returned by parse_expr() or parse_rexpr().
|
||||||
|
#
|
||||||
|
if re.match('[ \t]|/\*|@', t):
|
||||||
|
return 'space'
|
||||||
|
if re.match('Glo\(', t):
|
||||||
|
return 'gloid'
|
||||||
|
if re.match('Loc\(', t):
|
||||||
|
return 'locid'
|
||||||
|
if re.match('"', t):
|
||||||
|
return 'string'
|
||||||
|
if re.match(g_ccid0, t):
|
||||||
|
return 'id'
|
||||||
|
if re.match('[0-9]+[bf]', t):
|
||||||
|
return 'label'
|
||||||
|
if re.match('[0-9]', t):
|
||||||
|
return 'number'
|
||||||
|
return t # Sui generis
|
||||||
|
|
||||||
|
|
||||||
|
def debug_parse(a, b, c):
|
||||||
|
# Show results of instuction stream parse.
|
||||||
|
#
|
||||||
|
(b1, b2, b3) = parse_iparts(b)
|
||||||
|
newb = '{' + b1 + '}' + '{' + b2 + '}' + '{' + b3 + '}'
|
||||||
|
sys.stdout.write('{' + a + '}' + newb + c)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
instrs = parse_instrs(read_input())
|
||||||
|
instrs = explicit_address_loads(instrs)
|
||||||
|
instrs = funtypes(instrs)
|
||||||
|
instrs = jump_tables(instrs)
|
||||||
|
instrs = global_symbols(instrs)
|
||||||
|
instrs = local_symbols(instrs)
|
||||||
|
instrs = dot_relative(instrs)
|
||||||
|
instrs = add_prefix(instrs)
|
||||||
|
for (a, b, c) in instrs:
|
||||||
|
sys.stdout.write(a + b + c)
|
||||||
|
|
||||||
|
|
||||||
|
main()
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
if [ -z "$O3" ]; then
|
||||||
|
echo O3 var must point to ovpn3 tree
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -z "$TARGET" ]; then
|
||||||
|
echo TARGET var must be defined
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -z "$DL" ] && DL=~/Downloads
|
||||||
|
|
||||||
|
. $O3/core/vars/vars-$TARGET
|
||||||
|
. $O3/core/deps/lib-versions
|
||||||
|
|
||||||
|
# Build ASM files with clang 3.0
|
||||||
|
if [ "$APPLE_FAMILY" = "1" ]; then
|
||||||
|
GCC_AS_CMD=$HOME/clang3/clang
|
||||||
|
if ! [ -f "$GCC_AS_CMD" ]; then
|
||||||
|
echo "clang 3.0 binary must be present in $GCC_AS_CMD to assemble ARM crypto algorithms"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
DEST=minicrypto/minicrypto-$PLATFORM
|
||||||
|
|
||||||
|
GLOBAL_COMPILE_FLAGS="$PLATFORM_FLAGS $OTHER_COMPILER_FLAGS $LIB_OPT_LEVEL $LIB_FPIC -DSHA1_ASM -DBF_PTR -DOPENSSL_VERSION_PTEXT= -D__LP32__"
|
||||||
|
|
||||||
|
[ -z "$GCC_CMD" ] && GCC_CMD=gcc
|
||||||
|
[ -z "$GCC_AS_CMD" ] && GCC_AS_CMD="$GCC_CMD"
|
||||||
|
[ -z "$AR_CMD" ] && AR_CMD=ar
|
||||||
|
# the directory where this script lives
|
||||||
|
H=$O3/core/deps/minicrypto
|
||||||
|
|
||||||
|
if [ "$NO_WIPE" != "1" ]; then
|
||||||
|
# unzip OpenSSL
|
||||||
|
rm -rf $OPENSSL_VERSION
|
||||||
|
tar xfz $DL/$OPENSSL_VERSION.tar.gz
|
||||||
|
fi
|
||||||
|
|
||||||
|
OPENSSL_DIR=$(pwd)/$OPENSSL_VERSION
|
||||||
|
|
||||||
|
# make build directory
|
||||||
|
mkdir -p minicrypto
|
||||||
|
rm -rf minicrypto/minicrypto-$PLATFORM
|
||||||
|
mkdir -p minicrypto/minicrypto-$PLATFORM/build.tmp
|
||||||
|
cd minicrypto/minicrypto-$PLATFORM/build.tmp
|
||||||
|
mkdir openssl
|
||||||
|
|
||||||
|
# copy files from OpenSSL tree
|
||||||
|
|
||||||
|
# ARM
|
||||||
|
cp $OPENSSL_DIR/crypto/arm_arch.h .
|
||||||
|
|
||||||
|
# SHA general
|
||||||
|
cp $OPENSSL_DIR/crypto/md32_common.h .
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/sha.h openssl
|
||||||
|
|
||||||
|
# AES
|
||||||
|
cp $OPENSSL_DIR/crypto/aes/asm/aes-armv4.pl .
|
||||||
|
|
||||||
|
# SHA1
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/asm/sha1-armv4-large.pl .
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/sha_locl.h .
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/sha1dgst.c .
|
||||||
|
|
||||||
|
# SHA2
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/sha256.c .
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/asm/sha256-armv4.pl .
|
||||||
|
|
||||||
|
# SHA4
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/sha512.c .
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/asm/sha512-armv4.pl .
|
||||||
|
|
||||||
|
# note that OPENSSL_cleanse is not used by any
|
||||||
|
# of the functions we are interested in
|
||||||
|
cat >openssl/crypto.h <<EOF
|
||||||
|
#define fips_md_init(alg) fips_md_init_ctx(alg, alg)
|
||||||
|
#define fips_md_init_ctx(alg, cx) int alg##_Init(cx##_CTX *c)
|
||||||
|
#define OPENSSL_cleanse(ptr, len) memset((ptr), 0, (len))
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# irrelevant headers
|
||||||
|
touch openssl/e_os2.h
|
||||||
|
touch openssl/opensslconf.h
|
||||||
|
touch openssl/opensslv.h
|
||||||
|
touch aes_locl.h
|
||||||
|
touch cryptlib.h
|
||||||
|
touch crypto.h
|
||||||
|
|
||||||
|
# patches
|
||||||
|
patch <$H/aes-armv4.pl.patch
|
||||||
|
patch <$H/sha512-armv4.pl.patch
|
||||||
|
perl -pi -e 's/private_//g' aes-armv4.pl
|
||||||
|
for f in aes-armv4.pl sha256-armv4.pl sha512-armv4.pl ; do # armv4cpuid.pre
|
||||||
|
perl -pi -e 's/^(\.code.*)$/\/* \1 *\//' $f
|
||||||
|
done
|
||||||
|
|
||||||
|
# build C files
|
||||||
|
for f in *.c ; do
|
||||||
|
COMPILE_FLAGS="-Wno-unused-value"
|
||||||
|
CMD="$GCC_CMD $GLOBAL_COMPILE_FLAGS $COMPILE_FLAGS -I. -c $f"
|
||||||
|
echo $CMD
|
||||||
|
$CMD
|
||||||
|
done
|
||||||
|
|
||||||
|
# build armv4cpuid.S
|
||||||
|
#$O3/core/deps/minicrypto/arm-as-to-ios <armv4cpuid.pre >armv4cpuid.S
|
||||||
|
#CMD="$GCC_AS_CMD $GLOBAL_COMPILE_FLAGS -DSYS_macosx -DNO_THUMB -c armv4cpuid.S"
|
||||||
|
#echo $CMD
|
||||||
|
#$CMD
|
||||||
|
|
||||||
|
# build the ASM files given as perl source
|
||||||
|
for f in *.pl ; do
|
||||||
|
bn=${f%%.pl}
|
||||||
|
S=$bn.S
|
||||||
|
COMPILE_FLAGS=""
|
||||||
|
CVT_FLAGS=""
|
||||||
|
if [ "$APPLE_FAMILY" = "1" ]; then
|
||||||
|
COMPILE_FLAGS="$COMPILE_FLAGS -DNO_THUMB"
|
||||||
|
[ "$bn" = "aes-armv4" ] && CVT_FLAGS="$CVT_FLAGS --global=!ad1,!ad2,!ad3"
|
||||||
|
[ "$bn" = "sha512-armv4" ] && CVT_FLAGS="$CVT_FLAGS --global=!HI,!LO"
|
||||||
|
perl $f | $O3/core/deps/minicrypto/arm-as-to-ios --stdin $CVT_FLAGS >$S
|
||||||
|
else
|
||||||
|
perl $f >$S
|
||||||
|
fi
|
||||||
|
CMD="$GCC_AS_CMD $GLOBAL_COMPILE_FLAGS $COMPILE_FLAGS -DSYS_macosx -c $S"
|
||||||
|
echo $CMD
|
||||||
|
$CMD
|
||||||
|
done
|
||||||
|
|
||||||
|
CMD="$AR_CMD crs ../libminicrypto.a *.o"
|
||||||
|
echo $CMD
|
||||||
|
$CMD
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
if [ -z "$O3" ]; then
|
||||||
|
echo O3 var must point to ovpn3 tree
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -z "$TARGET" ]; then
|
||||||
|
echo TARGET var must be defined
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -z "$ARCH" ]; then
|
||||||
|
echo "ARCH var must be defined (x86_64|i386)"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -z "$DL" ] && DL=~/Downloads
|
||||||
|
|
||||||
|
. $O3/core/vars-$TARGET
|
||||||
|
. $O3/core/deps/lib-versions
|
||||||
|
|
||||||
|
DEST=minicrypto/minicrypto-$PLATFORM
|
||||||
|
|
||||||
|
GLOBAL_COMPILE_FLAGS="$MIN_DEPLOY_TARGET $OTHER_COMPILER_FLAGS $LIB_OPT_LEVEL $LIB_FPIC"
|
||||||
|
|
||||||
|
[ -z "$GCC_CMD" ] && GCC_CMD=gcc
|
||||||
|
[ -z "$GCC_AS_CMD" ] && GCC_AS_CMD="$GCC_CMD"
|
||||||
|
[ -z "$AR_CMD" ] && AR_CMD=ar
|
||||||
|
|
||||||
|
# the directory where this script lives
|
||||||
|
H=$O3/core/deps/minicrypto
|
||||||
|
|
||||||
|
if [ "$NO_WIPE" != "1" ]; then
|
||||||
|
# unzip OpenSSL
|
||||||
|
rm -rf $OPENSSL_VERSION
|
||||||
|
tar xfz $DL/$OPENSSL_VERSION.tar.gz
|
||||||
|
fi
|
||||||
|
|
||||||
|
OPENSSL_DIR=$(pwd)/$OPENSSL_VERSION
|
||||||
|
|
||||||
|
# make build directory
|
||||||
|
mkdir -p minicrypto
|
||||||
|
rm -rf minicrypto/minicrypto-$PLATFORM/$ARCH
|
||||||
|
mkdir -p minicrypto/minicrypto-$PLATFORM/$ARCH/build.tmp
|
||||||
|
cd minicrypto/minicrypto-$PLATFORM/$ARCH/build.tmp
|
||||||
|
mkdir openssl
|
||||||
|
|
||||||
|
# copy files from OpenSSL tree
|
||||||
|
|
||||||
|
# AES (not necessary now that PolarSSL has AES optimizations)
|
||||||
|
#cp $OPENSSL_DIR/crypto/aes/asm/aesni-x86_64.pl .
|
||||||
|
|
||||||
|
if [ "$ARCH" = "x86_64" ]; then
|
||||||
|
# General
|
||||||
|
cp $O3/core/deps/polarssl/intel_cpu.c .
|
||||||
|
cp $OPENSSL_DIR/crypto/perlasm/x86_64-xlate.pl .
|
||||||
|
cp $OPENSSL_DIR/crypto/x86_64cpuid.pl .
|
||||||
|
|
||||||
|
# SHA general
|
||||||
|
cp $OPENSSL_DIR/crypto/md32_common.h .
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/sha.h openssl
|
||||||
|
|
||||||
|
# SHA1
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/sha_locl.h .
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/sha1dgst.c .
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/asm/sha1-x86_64.pl .
|
||||||
|
|
||||||
|
# SHA256
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/sha256.c .
|
||||||
|
|
||||||
|
# SHA512
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/sha512.c .
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/asm/sha512-x86_64.pl .
|
||||||
|
|
||||||
|
# convert perl ASM to .s
|
||||||
|
for f in x86_64cpuid sha1-x86_64 ; do
|
||||||
|
perl $f.pl macosx >$f.s
|
||||||
|
done
|
||||||
|
perl sha512-x86_64.pl macosx sha512-x86_64.s
|
||||||
|
perl sha512-x86_64.pl macosx sha256-x86_64.s
|
||||||
|
elif [ "$ARCH" = "i386" ]; then
|
||||||
|
# General
|
||||||
|
cp $O3/core/deps/polarssl/intel_cpu.c .
|
||||||
|
cp $OPENSSL_DIR/crypto/perlasm/x86asm.pl .
|
||||||
|
cp $OPENSSL_DIR/crypto/perlasm/x86gas.pl .
|
||||||
|
cp $OPENSSL_DIR/crypto/x86cpuid.pl .
|
||||||
|
|
||||||
|
# SHA general
|
||||||
|
cp $OPENSSL_DIR/crypto/md32_common.h .
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/sha.h openssl
|
||||||
|
|
||||||
|
# SHA1
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/sha_locl.h .
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/sha1dgst.c .
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/asm/sha1-586.pl .
|
||||||
|
|
||||||
|
# SHA256
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/sha256.c .
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/asm/sha256-586.pl .
|
||||||
|
|
||||||
|
# SHA512
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/sha512.c .
|
||||||
|
cp $OPENSSL_DIR/crypto/sha/asm/sha512-586.pl .
|
||||||
|
|
||||||
|
# convert perl ASM to .s
|
||||||
|
for f in x86cpuid sha1-586 sha256-586 sha512-586 ; do
|
||||||
|
perl $f.pl macosx >$f.s
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat >openssl/crypto.h <<EOF
|
||||||
|
#define fips_md_init(alg) fips_md_init_ctx(alg, alg)
|
||||||
|
#define fips_md_init_ctx(alg, cx) int alg##_Init(cx##_CTX *c)
|
||||||
|
void OPENSSL_cleanse(void *ptr, unsigned long len);
|
||||||
|
#define OPENSSL_VERSION_PTEXT " minicrypto"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# irrelevant headers
|
||||||
|
touch openssl/e_os2.h
|
||||||
|
touch openssl/opensslconf.h
|
||||||
|
touch openssl/opensslv.h
|
||||||
|
touch aes_locl.h
|
||||||
|
touch cryptlib.h
|
||||||
|
touch crypto.h
|
||||||
|
|
||||||
|
# build C/ASM files
|
||||||
|
for f in *.c *.s ; do
|
||||||
|
COMPILE_FLAGS="-arch $ARCH -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM"
|
||||||
|
CMD="$GCC_CMD $GLOBAL_COMPILE_FLAGS $COMPILE_FLAGS -I. -c $f"
|
||||||
|
echo $CMD
|
||||||
|
$CMD
|
||||||
|
done
|
||||||
|
|
||||||
|
CMD="$AR_CMD crs ../libminicrypto.a *.o"
|
||||||
|
echo $CMD
|
||||||
|
$CMD
|
||||||
|
echo SYMBOLS
|
||||||
|
nm ../libminicrypto.a
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
--- sha512-armv4.pl.orig 2012-09-03 13:21:35.000000000 -0600
|
||||||
|
+++ sha512-armv4.pl 2012-09-03 13:50:08.000000000 -0600
|
||||||
|
@@ -220,9 +220,6 @@
|
||||||
|
WORD64(0x4cc5d4be,0xcb3e42b6, 0x597f299c,0xfc657e2a)
|
||||||
|
WORD64(0x5fcb6fab,0x3ad6faec, 0x6c44198c,0x4a475817)
|
||||||
|
.size K512,.-K512
|
||||||
|
-.LOPENSSL_armcap:
|
||||||
|
-.word OPENSSL_armcap_P-sha512_block_data_order
|
||||||
|
-.skip 32-4
|
||||||
|
|
||||||
|
.global sha512_block_data_order
|
||||||
|
.type sha512_block_data_order,%function
|
||||||
|
@@ -230,10 +227,7 @@
|
||||||
|
sub r3,pc,#8 @ sha512_block_data_order
|
||||||
|
add $len,$inp,$len,lsl#7 @ len to point at the end of inp
|
||||||
|
#if __ARM_ARCH__>=7
|
||||||
|
- ldr r12,.LOPENSSL_armcap
|
||||||
|
- ldr r12,[r3,r12] @ OPENSSL_armcap_P
|
||||||
|
- tst r12,#1
|
||||||
|
- bne .LNEON
|
||||||
|
+ b .LNEON @ JY -- assume ARM v7 always supports NEON
|
||||||
|
#endif
|
||||||
|
stmdb sp!,{r4-r12,lr}
|
||||||
|
sub $Ktbl,r3,#672 @ K512
|
||||||
|
@@ -573,7 +567,6 @@
|
||||||
|
.size sha512_block_data_order,.-sha512_block_data_order
|
||||||
|
.asciz "SHA512 block transform for ARMv4/NEON, CRYPTOGAMS by <appro\@openssl.org>"
|
||||||
|
.align 2
|
||||||
|
-.comm OPENSSL_armcap_P,4,4
|
||||||
|
___
|
||||||
|
|
||||||
|
$code =~ s/\`([^\`]*)\`/eval $1/gem;
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
if [ -z "$O3" ]; then
|
||||||
|
echo O3 var must point to ovpn3 tree
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -z "$TARGET" ]; then
|
||||||
|
echo TARGET var must be defined
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -z "$OPENSSL_TARGET" ]; then
|
||||||
|
echo "OPENSSL_TARGET var must be defined"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# GNU sed differs from BSD sed
|
||||||
|
if sed --version 2>&1 | grep -q GNU ; then
|
||||||
|
mysed='sed -i'
|
||||||
|
else
|
||||||
|
mysed='sed -i ""'
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -z "$GCC_CMD" ] && GCC_CMD=gcc
|
||||||
|
|
||||||
|
[ -z "$LINK_MODE" ] && LINK_MODE=static
|
||||||
|
[ "$LINK_MODE" = "static" ] && LINK_MODE=no-shared
|
||||||
|
|
||||||
|
[ -z "$DL" ] && DL=~/Downloads
|
||||||
|
|
||||||
|
. $O3/core/vars/vars-$TARGET
|
||||||
|
. $O3/core/deps/lib-versions
|
||||||
|
|
||||||
|
AR=ar
|
||||||
|
RANLIB=ranlib
|
||||||
|
[ "$AR_CMD" ] && AR=$AR_CMD
|
||||||
|
[ "$RANLIB_CMD" ] && RANLIB=$RANLIB_CMD
|
||||||
|
|
||||||
|
# special hack because OpenSSL build system doesn't use rc options for ar
|
||||||
|
[ "$AR" = "gcc-ar" ] && AR="gcc-ar rc"
|
||||||
|
[ "$AR" = "gcc-ar-5" ] && AR="gcc-ar-5 rc"
|
||||||
|
|
||||||
|
OPENSSL=$OPENSSL_VERSION
|
||||||
|
DIST=$(pwd)/openssl/openssl-$PLATFORM
|
||||||
|
[ "$ARCH" ] && DIST=$DIST/$ARCH
|
||||||
|
rm -rf $OPENSSL $DIST
|
||||||
|
mkdir -p $DIST
|
||||||
|
tar xfz $DL/$OPENSSL.tar.gz
|
||||||
|
pushd $OPENSSL
|
||||||
|
CMD="./Configure $OPENSSL_TARGET $LINK_MODE threads no-idea no-mdc2 no-rc5 --prefix=$DIST"
|
||||||
|
echo $CMD
|
||||||
|
$CMD
|
||||||
|
$mysed -e "s|-O3|$LIB_OPT_LEVEL $MIN_DEPLOY_TARGET $OTHER_COMPILER_FLAGS $LIB_FPIC|" Makefile
|
||||||
|
#$mysed -e "s|ERR_load_COMP_strings()|//ERR_load_COMP_strings()|" crypto/err/err_all.c
|
||||||
|
make depend
|
||||||
|
make CC="$GCC_CMD" AR="$AR" RANLIB="$RANLIB" -j ${MAKE_JOBS:-1} build_libs
|
||||||
|
touch apps/openssl
|
||||||
|
touch openssl.pc
|
||||||
|
touch libcrypto.pc
|
||||||
|
touch libssl.pc
|
||||||
|
make install_sw
|
||||||
|
popd
|
||||||
|
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
polartmp
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
cmake_minimum_required(VERSION 2.6)
|
||||||
|
project(POLARSSL C)
|
||||||
|
|
||||||
|
enable_testing()
|
||||||
|
|
||||||
|
if(CMAKE_COMPILER_IS_GNUCC)
|
||||||
|
# JY Added
|
||||||
|
set(CMAKE_OSX_ARCHITECTURES "")
|
||||||
|
set(CMAKE_OSX_DEPLOYMENT_TARGET "")
|
||||||
|
set(CMAKE_OSX_SYSROOT "")
|
||||||
|
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} $ENV{LIB_FPIC} $ENV{LIB_OPT_LEVEL} $ENV{PLATFORM_FLAGS} $ENV{OTHER_COMPILER_FLAGS} -Wall -W -Wdeclaration-after-statement")
|
||||||
|
if (NOT "$ENV{GCC_CMD}" STREQUAL "")
|
||||||
|
set(CMAKE_C_COMPILER "$ENV{GCC_CMD}")
|
||||||
|
endif()
|
||||||
|
if (NOT "$ENV{GPP_CMD}" STREQUAL "")
|
||||||
|
set(CMAKE_CXX_COMPILER "$ENV{GPP_CMD}")
|
||||||
|
endif()
|
||||||
|
if (NOT "$ENV{AR_CMD}" STREQUAL "")
|
||||||
|
set(CMAKE_AR "$ENV{AR_CMD}")
|
||||||
|
endif()
|
||||||
|
if (NOT "$ENV{RANLIB_CMD}" STREQUAL "")
|
||||||
|
set(CMAKE_RANLIB "$ENV{RANLIB_CMD}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# JY Commented out
|
||||||
|
#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O2 -Wall -Wextra -W -Wdeclaration-after-statement")
|
||||||
|
#set(CMAKE_C_FLAGS_DEBUG "-g3 -O0")
|
||||||
|
#set(CMAKE_C_FLAGS_COVERAGE "-g3 -O0 -fprofile-arcs -ftest-coverage -lgcov")
|
||||||
|
endif(CMAKE_COMPILER_IS_GNUCC)
|
||||||
|
|
||||||
|
if(CMAKE_BUILD_TYPE STREQUAL "Coverage")
|
||||||
|
if(CMAKE_COMPILER_IS_GNUCC)
|
||||||
|
set(CMAKE_SHARED_LINKER_FLAGS "-fprofile-arcs -ftest-coverage")
|
||||||
|
endif(CMAKE_COMPILER_IS_GNUCC)
|
||||||
|
endif(CMAKE_BUILD_TYPE STREQUAL "Coverage")
|
||||||
|
|
||||||
|
option(USE_PKCS11_HELPER_LIBRARY "Build PolarSSL with the pkcs11-helper library." OFF)
|
||||||
|
|
||||||
|
option(ENABLE_ZLIB_SUPPORT "Build PolarSSL with zlib library." OFF)
|
||||||
|
|
||||||
|
# JY added
|
||||||
|
if(MINICRYPTO)
|
||||||
|
if(MINICRYPTO_DIR)
|
||||||
|
add_library(minicrypto STATIC IMPORTED)
|
||||||
|
set_property(TARGET minicrypto PROPERTY IMPORTED_LOCATION "${MINICRYPTO_DIR}/libminicrypto.a")
|
||||||
|
endif()
|
||||||
|
if(OSSLCRYPTO_DIR)
|
||||||
|
add_library(crypto STATIC IMPORTED)
|
||||||
|
set_property(TARGET crypto PROPERTY IMPORTED_LOCATION "${OSSLCRYPTO_DIR}/libcrypto.a")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# include full testing infrastructure (JY added)
|
||||||
|
if(ENABLE_TESTING)
|
||||||
|
enable_testing()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(LIB_INSTALL_DIR)
|
||||||
|
else()
|
||||||
|
set(LIB_INSTALL_DIR lib)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include_directories(include/)
|
||||||
|
|
||||||
|
if(ENABLE_ZLIB_SUPPORT)
|
||||||
|
find_package(ZLIB)
|
||||||
|
|
||||||
|
if(ZLIB_FOUND)
|
||||||
|
include_directories(ZLIB_INCLUDE_DIR)
|
||||||
|
endif(ZLIB_FOUND)
|
||||||
|
endif(ENABLE_ZLIB_SUPPORT)
|
||||||
|
|
||||||
|
add_subdirectory(library)
|
||||||
|
add_subdirectory(include)
|
||||||
|
|
||||||
|
# include full testing infrastructure (JY modified)
|
||||||
|
if(ENABLE_TESTING)
|
||||||
|
if(CMAKE_COMPILER_IS_GNUCC)
|
||||||
|
add_subdirectory(tests)
|
||||||
|
endif(CMAKE_COMPILER_IS_GNUCC)
|
||||||
|
add_subdirectory(programs)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
ADD_CUSTOM_TARGET(apidoc
|
||||||
|
COMMAND doxygen doxygen/polarssl.doxyfile
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
Building PolarSSL for android.
|
||||||
|
|
||||||
|
First, build static OpenSSL for PolarSSL/OpenSSL bridge
|
||||||
|
(the build-openssl-small script may be used).
|
||||||
|
|
||||||
|
Next build libminicrypto.a from libcrypto.a :
|
||||||
|
|
||||||
|
$O3/polarssl/build-mini-openssl ref
|
||||||
|
|
||||||
|
Finally, build PolarSSL:
|
||||||
|
|
||||||
|
TARGET=android $O3/polarssl/build-polarssl
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# this one is important
|
||||||
|
SET(CMAKE_SYSTEM_NAME Linux)
|
||||||
|
#this one not so much
|
||||||
|
SET(CMAKE_SYSTEM_VERSION 1)
|
||||||
|
|
||||||
|
# specify the cross compiler (assumes that PATH already points to android toolchain)
|
||||||
|
SET(CMAKE_C_COMPILER gcc)
|
||||||
|
SET(CMAKE_CXX_COMPILER g++)
|
||||||
|
|
||||||
|
# where is the target environment
|
||||||
|
#SET(CMAKE_FIND_ROOT_PATH /opt/eldk-2007-01-19/ppc_74xx /home/alex/eldk-ppc74xx-inst)
|
||||||
|
|
||||||
|
# search for programs in the build host directories
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
# for libraries and headers in the target directories
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# specify the cross compiler
|
||||||
|
SET(CMAKE_C_COMPILER clang)
|
||||||
|
SET(CMAKE_CXX_COMPILER clang++)
|
||||||
|
SET(CMAKE_COMPILER_IS_GNUCC 1)
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
diff -uNr polarssl-1.2.7/include/polarssl/bn_mul.h polarssl-1.2.7.new/include/polarssl/bn_mul.h
|
||||||
|
--- polarssl-1.2.7/include/polarssl/bn_mul.h 2013-04-13 03:56:17.000000000 -0600
|
||||||
|
+++ polarssl-1.2.7.new/include/polarssl/bn_mul.h 2013-06-13 16:30:35.000000000 -0600
|
||||||
|
@@ -548,7 +548,7 @@
|
||||||
|
|
||||||
|
#if defined(__arm__)
|
||||||
|
|
||||||
|
-#if defined(__thumb__)
|
||||||
|
+#if defined(__thumb__) && !defined(__thumb2__)
|
||||||
|
|
||||||
|
#define MULADDC_INIT \
|
||||||
|
asm( \
|
||||||
|
diff -uNr polarssl-1.2.7/library/bignum.c polarssl-1.2.7.new/library/bignum.c
|
||||||
|
--- polarssl-1.2.7/library/bignum.c 2013-04-13 03:56:17.000000000 -0600
|
||||||
|
+++ polarssl-1.2.7.new/library/bignum.c 2013-06-13 16:30:35.000000000 -0600
|
||||||
|
@@ -935,7 +935,15 @@
|
||||||
|
/*
|
||||||
|
* Helper for mpi multiplication
|
||||||
|
*/
|
||||||
|
-static void mpi_mul_hlp( size_t i, t_uint *s, t_uint *d, t_uint b )
|
||||||
|
+static
|
||||||
|
+#if defined(__APPLE__) && defined(__arm__)
|
||||||
|
+/*
|
||||||
|
+ * Apple LLVM version 4.2 (clang-425.0.24) (based on LLVM 3.2svn)
|
||||||
|
+ * appears to need this to prevent bad ARM code generation at -O3.
|
||||||
|
+ */
|
||||||
|
+__attribute__ ((noinline))
|
||||||
|
+#endif
|
||||||
|
+void mpi_mul_hlp( size_t i, t_uint *s, t_uint *d, t_uint b )
|
||||||
|
{
|
||||||
|
t_uint c = 0, t = 0;
|
||||||
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
. $O3/core/deps/lib-versions
|
||||||
|
POLARSSL_SRC=$HOME/src/mac/$POLARSSL_VERSION
|
||||||
|
PD=$O3/core/deps/polarssl
|
||||||
|
PB=$(basename $POLARSSL_SRC)
|
||||||
|
|
||||||
|
rm -rf polartmp
|
||||||
|
mkdir polartmp
|
||||||
|
cd polartmp
|
||||||
|
cp -a $POLARSSL_SRC polarssl.new
|
||||||
|
|
||||||
|
# extract the PolarSSL source
|
||||||
|
tar xfz $DL/$PB-gpl.tgz
|
||||||
|
|
||||||
|
cd $PB
|
||||||
|
rm $(find . -type f | grep -E 'Makefile|\.orig$|\.rej$')
|
||||||
|
rm -f CMakeLists.txt include/polarssl/config.h include/polarssl/openvpn-polarssl.h
|
||||||
|
|
||||||
|
cd ../polarssl.new
|
||||||
|
rm -f CMakeLists.txt include/polarssl/config.h include/polarssl/openvpn-polarssl.h
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
diff -ur $PB polarssl.new | grep -v '^Only in'
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Examples:
|
||||||
|
# $O3/core/deps/polarssl/build-mini-openssl ref
|
||||||
|
# $O3/core/deps/polarssl/build-mini-openssl ref-aesni
|
||||||
|
|
||||||
|
set -e
|
||||||
|
if [ -z "$1" ]; then
|
||||||
|
echo "usage: build-mini-openssl <ref|ref-aesni>"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -z "$OPENSSL_DIR" ]; then
|
||||||
|
echo OPENSSL_DIR must be defined
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$APPLE_FAMILY" = "1" ] && [ -z "$GCC_CMD" ]; then
|
||||||
|
GCC_CMD=clang
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$APPLE_FAMILY" = "1" ]; then
|
||||||
|
NM_FLAGS=-P
|
||||||
|
BSD_SYMBOLS="1"
|
||||||
|
VISIBILITY="-fvisibility=hidden"
|
||||||
|
else
|
||||||
|
NM_FLAGS="-f posix"
|
||||||
|
BSD_SYMBOLS="0"
|
||||||
|
VISIBILITY=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -z "$NM_CMD" ] && NM_CMD=nm
|
||||||
|
[ -z "$AR_CMD" ] && AR_CMD=ar
|
||||||
|
[ -z "$GCC_CMD" ] && GCC_CMD=gcc
|
||||||
|
PD=$O3/core/deps/polarssl
|
||||||
|
cd $OPENSSL_DIR
|
||||||
|
cd lib
|
||||||
|
rm -rf tmp
|
||||||
|
mkdir tmp
|
||||||
|
$NM_CMD $NM_FLAGS libcrypto.a >tmp/nm-file
|
||||||
|
echo "NOTE: on BSD systems, don't worry about any 'no name list' errors above"
|
||||||
|
cd tmp
|
||||||
|
python $O3/common/scripts/sym.py $PD/$1 nm-file $AR_CMD ../libcrypto.a libminicrypto.a buildmini ../mini-undef.sh $BSD_SYMBOLS
|
||||||
|
. buildmini
|
||||||
|
|
||||||
|
# need any special initialization?
|
||||||
|
. ../mini-undef.sh
|
||||||
|
if [ "$SYM_UNDEF_OPENSSL_ia32cap_P" ] && [ "$SYM_UNDEF_OPENSSL_cpuid_setup" ]; then
|
||||||
|
echo BUILDING STUB intel_cpu.c
|
||||||
|
$GCC_CMD $VISIBILITY $LIB_OPT_LEVEL $LIB_FPIC -c $PD/intel_cpu.c
|
||||||
|
$AR_CMD rs libminicrypto.a intel_cpu.o
|
||||||
|
fi
|
||||||
|
|
||||||
|
mv libminicrypto.a ..
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
#
|
||||||
|
# Parameters:
|
||||||
|
# CMAKE_TARGET -- use $CMAKE_TARGET.cmake as toolchain file
|
||||||
|
# AES_NI=1 -- enable AES_NI processor optimization
|
||||||
|
# EXTERNAL_RNG=1 -- disable all internal RNG implementations (caller must provide)
|
||||||
|
# ENABLE_TESTING=1 -- run PolarSSL test scripts after build
|
||||||
|
# DEBUG_BUILD=1 or SELF_TEST=1 -- enable minimal testing on target
|
||||||
|
# ENABLE_SERVER=1 -- enable SSL/TLS server code
|
||||||
|
# ENABLE_FS_IO=1 -- enable PolarSSL file I/O
|
||||||
|
# VERBOSE=1 -- see build commands
|
||||||
|
# USE_MINICRYPTO=1 -- use minicrypto library
|
||||||
|
# NO_WIPE=1 -- don't wipe source tree and reunzip tarball
|
||||||
|
# STOCK_CONFIG=1 -- use stock PolarSSL config.h
|
||||||
|
|
||||||
|
set -e
|
||||||
|
if [ -z "$O3" ]; then
|
||||||
|
echo O3 var must point to ovpn3 tree
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -z "$TARGET" ]; then
|
||||||
|
echo TARGET var must be defined
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# source vars
|
||||||
|
. $O3/core/vars/vars-${TARGET}
|
||||||
|
. $O3/core/deps/lib-versions
|
||||||
|
|
||||||
|
# extract the PolarSSL source
|
||||||
|
PD=$O3/core/deps/polarssl
|
||||||
|
DIST=polarssl-$PLATFORM
|
||||||
|
|
||||||
|
rm -rf $DIST
|
||||||
|
mkdir $DIST
|
||||||
|
|
||||||
|
if [ "$NO_WIPE" = "1" ]; then
|
||||||
|
echo RETAIN existing source
|
||||||
|
cd $POLARSSL_VERSION
|
||||||
|
elif [ "$NO_WIPE" = "partial" ]; then
|
||||||
|
echo RETAIN existing source but copy config.h and CMakeLists.txt
|
||||||
|
cd $POLARSSL_VERSION
|
||||||
|
|
||||||
|
# define configs
|
||||||
|
if [ "$STOCK_CONFIG" != "1" ]; then
|
||||||
|
cp $PD/config.h include/polarssl/
|
||||||
|
fi
|
||||||
|
cp $PD/CMakeLists.txt .
|
||||||
|
else
|
||||||
|
echo WIPE and reunzip source
|
||||||
|
rm -rf $POLARSSL_VERSION $POLARSSL_VERSION-prerelease
|
||||||
|
[ -z "$DL" ] && DL=~/Downloads
|
||||||
|
tar xfz $DL/$POLARSSL_VERSION-gpl.tgz
|
||||||
|
|
||||||
|
[ -d $POLARSSL_VERSION-prerelease ] && mv $POLARSSL_VERSION-prerelease $POLARSSL_VERSION
|
||||||
|
cd $POLARSSL_VERSION
|
||||||
|
|
||||||
|
# delete makefiles (apparently not needed)
|
||||||
|
rm $(find . -type f | grep Makefile)
|
||||||
|
|
||||||
|
patch -p1 <$PD/relaxed-x509-date.patch
|
||||||
|
#patch -p1 <$PD/dhm.patch
|
||||||
|
#patch -p1 <$PD/entropy-printf.patch
|
||||||
|
|
||||||
|
if [ "$USE_MINICRYPTO" = "1" ]; then
|
||||||
|
# do the big polar-openssl patch
|
||||||
|
echo MERGING polarssl-minicrypto.patch
|
||||||
|
patch -p1 <$PD/polarssl-minicrypto.patch
|
||||||
|
fi
|
||||||
|
|
||||||
|
# define configs
|
||||||
|
cp include/polarssl/config.h include/polarssl/config.h.orig
|
||||||
|
cp CMakeLists.txt CMakeLists.txt.orig
|
||||||
|
cp $PD/config.h include/polarssl/
|
||||||
|
cp $PD/CMakeLists.txt .
|
||||||
|
fi
|
||||||
|
|
||||||
|
# dynamically generated header file with options,
|
||||||
|
# included by config.h
|
||||||
|
OPC=include/polarssl/openvpn-polarssl.h
|
||||||
|
echo '/* Automatically generated by ovpn3/core/deps/polarssl/build-polarssl, do not edit */' >$OPC
|
||||||
|
|
||||||
|
# set options
|
||||||
|
OPT=""
|
||||||
|
|
||||||
|
# relaxed cert checking
|
||||||
|
echo "#define POLARSSL_RELAXED_X509_DATE" >>$OPC
|
||||||
|
|
||||||
|
# RNG
|
||||||
|
if [ "$EXTERNAL_RNG" = "1" ]; then
|
||||||
|
echo "#define EXTERNAL_RNG" >>$OPC
|
||||||
|
fi
|
||||||
|
|
||||||
|
# enable full testing infrastructure
|
||||||
|
if [ "$ENABLE_TESTING" = "1" ]; then
|
||||||
|
OPT="$OPT -DENABLE_TESTING=1"
|
||||||
|
echo "#define ENABLE_TESTING" >>$OPC
|
||||||
|
fi
|
||||||
|
|
||||||
|
# enable minimal testing on target
|
||||||
|
if [ "$DEBUG_BUILD" = "1" ] || [ "$SELF_TEST" = "1" ]; then
|
||||||
|
echo "#define POLARSSL_SELF_TEST" >>$OPC
|
||||||
|
fi
|
||||||
|
|
||||||
|
# configure target
|
||||||
|
if [ "$CMAKE_TARGET" ]; then
|
||||||
|
OPT="$OPT -DCMAKE_TOOLCHAIN_FILE=$PD/$CMAKE_TARGET.cmake"
|
||||||
|
elif [ "$APPLE_FAMILY" = "1" ]; then
|
||||||
|
OPT="$OPT -DCMAKE_TOOLCHAIN_FILE=$PD/apple.cmake"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Minicrypto
|
||||||
|
if [ "$USE_MINICRYPTO" = "1" ]; then
|
||||||
|
OPT="$OPT -DMINICRYPTO=1"
|
||||||
|
if [ "$MINICRYPTO_DIR" ]; then
|
||||||
|
OPT="$OPT -DMINICRYPTO_DIR=$MINICRYPTO_DIR"
|
||||||
|
fi
|
||||||
|
if [ "$OSSLCRYPTO_DIR" ]; then
|
||||||
|
OPT="$OPT -DOSSLCRYPTO_DIR=$OSSLCRYPTO_DIR"
|
||||||
|
fi
|
||||||
|
if [ "$MINICRYPTO_NO_AES" != "1" ]; then
|
||||||
|
echo "#define POLARSSL_AES_ALT" >>$OPC
|
||||||
|
fi
|
||||||
|
echo "#define POLARSSL_SHA1_ALT" >>$OPC
|
||||||
|
echo "#define POLARSSL_SHA256_ALT" >>$OPC
|
||||||
|
echo "#define POLARSSL_SHA512_ALT" >>$OPC
|
||||||
|
if [ "$AES_NI" = "1" ] && [ "$MINICRYPTO_NO_AES" != "1" ]; then
|
||||||
|
echo "#define POLARSSL_USE_OPENSSL_AES_NI" >>$OPC
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Enable SSL/TLS server
|
||||||
|
if [ "$ENABLE_SERVER" = "1" ]; then
|
||||||
|
echo "#define POLARSSL_SSL_SRV_C" >>$OPC
|
||||||
|
fi
|
||||||
|
|
||||||
|
# enable PolarSSL file I/O
|
||||||
|
if [ "$ENABLE_FS_IO" = "1" ]; then
|
||||||
|
echo "#define POLARSSL_FS_IO" >>$OPC
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Build shared library
|
||||||
|
if [ "$SHARED" = "1" ]; then
|
||||||
|
OPT="$OPT -DUSE_SHARED_POLARSSL_LIBRARY=1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# echo options
|
||||||
|
echo OPTIONS $OPT
|
||||||
|
|
||||||
|
# build it
|
||||||
|
pwd
|
||||||
|
cd ../$DIST
|
||||||
|
cmake $OPT ../$POLARSSL_VERSION
|
||||||
|
if [ "$VERBOSE" = "1" ]; then
|
||||||
|
make VERBOSE=1
|
||||||
|
else
|
||||||
|
make
|
||||||
|
fi
|
||||||
|
|
||||||
|
# test it
|
||||||
|
if [ "$ENABLE_TESTING" = "1" ]; then
|
||||||
|
make test
|
||||||
|
fi
|
||||||
|
|
||||||
|
# copy headers
|
||||||
|
cp -a ../$POLARSSL_VERSION/include/polarssl include/
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -e
|
||||||
|
. $O3/core/deps/lib-versions
|
||||||
|
POLARSSL_SRC=$HOME/src/mac/$POLARSSL_VERSION
|
||||||
|
PD=$O3/core/deps/polarssl
|
||||||
|
PB=$(basename $POLARSSL_SRC)
|
||||||
|
|
||||||
|
rm -rf polartmp
|
||||||
|
mkdir polartmp
|
||||||
|
cd polartmp
|
||||||
|
cp -a $POLARSSL_SRC polarssl.new
|
||||||
|
|
||||||
|
# extract the PolarSSL source
|
||||||
|
tar xfz $DL/$PB-gpl.tgz
|
||||||
|
|
||||||
|
cd $PB
|
||||||
|
rm $(find . -type f | grep -E 'Makefile|\.orig$|\.rej$')
|
||||||
|
rm -f CMakeLists.txt include/polarssl/config.h include/polarssl/openvpn-polarssl.h
|
||||||
|
|
||||||
|
cd ../polarssl.new
|
||||||
|
rm -f CMakeLists.txt include/polarssl/config.h include/polarssl/openvpn-polarssl.h
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
if [ "$CRYPTO_ALT_PATCH" = "1" ]; then
|
||||||
|
diff -uNr $PB polarssl.new >$PD/polar-openssl.patch
|
||||||
|
cp $PD/crypto-alt.txt $PD/polarssl-crypto-alt.patch
|
||||||
|
diff -ur $PB polarssl.new | grep -v '^Only in' >>$PD/polarssl-crypto-alt.patch
|
||||||
|
else
|
||||||
|
diff -ur $PB polarssl.new | grep -v '^Only in'
|
||||||
|
fi
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,959 @@
|
|||||||
|
/**
|
||||||
|
* \file config.h
|
||||||
|
*
|
||||||
|
* \brief Configuration options (set of defines)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006-2012, Brainspark B.V.
|
||||||
|
*
|
||||||
|
* This file is part of PolarSSL (http://www.polarssl.org)
|
||||||
|
* Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 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 General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* This set of compile-time options may be used to enable
|
||||||
|
* or disable features selectively, and reduce the global
|
||||||
|
* memory footprint.
|
||||||
|
*/
|
||||||
|
#ifndef POLARSSL_CONFIG_H
|
||||||
|
#define POLARSSL_CONFIG_H
|
||||||
|
|
||||||
|
#include <polarssl/openvpn-polarssl.h>
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_DEPRECATE)
|
||||||
|
#define _CRT_SECURE_NO_DEPRECATE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \name SECTION: System support
|
||||||
|
*
|
||||||
|
* This section sets system specific settings.
|
||||||
|
* \{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_HAVE_INT8
|
||||||
|
*
|
||||||
|
* The system uses 8-bit wide native integers.
|
||||||
|
*
|
||||||
|
* Uncomment if native integers are 8-bit wide.
|
||||||
|
#define POLARSSL_HAVE_INT8
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_HAVE_INT16
|
||||||
|
*
|
||||||
|
* The system uses 16-bit wide native integers.
|
||||||
|
*
|
||||||
|
* Uncomment if native integers are 16-bit wide.
|
||||||
|
#define POLARSSL_HAVE_INT16
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_HAVE_LONGLONG
|
||||||
|
*
|
||||||
|
* The compiler supports the 'long long' type.
|
||||||
|
* (Only used on 32-bit platforms)
|
||||||
|
*/
|
||||||
|
#define POLARSSL_HAVE_LONGLONG
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_HAVE_ASM
|
||||||
|
*
|
||||||
|
* The compiler has support for asm()
|
||||||
|
*
|
||||||
|
* Uncomment to enable the use of assembly code.
|
||||||
|
*
|
||||||
|
* Requires support for asm() in compiler.
|
||||||
|
*
|
||||||
|
* Used in:
|
||||||
|
* library/timing.c
|
||||||
|
* library/padlock.c
|
||||||
|
* include/polarssl/bn_mul.h
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define POLARSSL_HAVE_ASM
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_HAVE_SSE2
|
||||||
|
*
|
||||||
|
* CPU supports SSE2 instruction set.
|
||||||
|
*
|
||||||
|
* Uncomment if the CPU supports SSE2 (IA-32 specific).
|
||||||
|
*
|
||||||
|
#define POLARSSL_HAVE_SSE2
|
||||||
|
*/
|
||||||
|
/* \} name */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \name SECTION: PolarSSL feature support
|
||||||
|
*
|
||||||
|
* This section sets support for features that are or are not needed
|
||||||
|
* within the modules that are enabled.
|
||||||
|
* \{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_AES_ROM_TABLES
|
||||||
|
*
|
||||||
|
* Store the AES tables in ROM.
|
||||||
|
*
|
||||||
|
* Uncomment this macro to store the AES tables in ROM.
|
||||||
|
*
|
||||||
|
#define POLARSSL_AES_ROM_TABLES
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_CIPHER_MODE_CFB
|
||||||
|
*
|
||||||
|
* Enable Cipher Feedback mode (CFB) for symmetric ciphers.
|
||||||
|
*/
|
||||||
|
// JY removed
|
||||||
|
//#define POLARSSL_CIPHER_MODE_CFB
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_CIPHER_MODE_CTR
|
||||||
|
*
|
||||||
|
* Enable Counter Block Cipher mode (CTR) for symmetric ciphers.
|
||||||
|
*/
|
||||||
|
// JY removed
|
||||||
|
//#define POLARSSL_CIPHER_MODE_CTR
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_CIPHER_NULL_CIPHER
|
||||||
|
*
|
||||||
|
* Enable NULL cipher.
|
||||||
|
* Warning: Only do so when you know what you are doing. This allows for
|
||||||
|
* encryption or channels without any security!
|
||||||
|
*
|
||||||
|
* Requires POLARSSL_ENABLE_WEAK_CIPHERSUITES as well to enable
|
||||||
|
* the following ciphersuites:
|
||||||
|
* TLS_RSA_WITH_NULL_MD5
|
||||||
|
* TLS_RSA_WITH_NULL_SHA
|
||||||
|
* TLS_RSA_WITH_NULL_SHA256
|
||||||
|
*
|
||||||
|
* Uncomment this macro to enable the NULL cipher and ciphersuites
|
||||||
|
#define POLARSSL_CIPHER_NULL_CIPHER
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_ENABLE_WEAK_CIPHERSUITES
|
||||||
|
*
|
||||||
|
* Enable weak ciphersuites in SSL / TLS
|
||||||
|
* Warning: Only do so when you know what you are doing. This allows for
|
||||||
|
* channels with virtually no security at all!
|
||||||
|
*
|
||||||
|
* This enables the following ciphersuites:
|
||||||
|
* TLS_RSA_WITH_DES_CBC_SHA
|
||||||
|
* TLS_DHE_RSA_WITH_DES_CBC_SHA
|
||||||
|
*
|
||||||
|
* Uncomment this macro to enable weak ciphersuites
|
||||||
|
#define POLARSSL_ENABLE_WEAK_CIPHERSUITES
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_ERROR_STRERROR_DUMMY
|
||||||
|
*
|
||||||
|
* Enable a dummy error function to make use of error_strerror() in
|
||||||
|
* third party libraries easier.
|
||||||
|
*
|
||||||
|
* Disable if you run into name conflicts and want to really remove the
|
||||||
|
* error_strerror()
|
||||||
|
*/
|
||||||
|
#define POLARSSL_ERROR_STRERROR_DUMMY
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_GENPRIME
|
||||||
|
*
|
||||||
|
* Requires: POLARSSL_BIGNUM_C, POLARSSL_RSA_C
|
||||||
|
*
|
||||||
|
* Enable the RSA prime-number generation code.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_GENPRIME
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_FS_IO
|
||||||
|
*
|
||||||
|
* Enable functions that use the filesystem.
|
||||||
|
*/
|
||||||
|
// JY removed
|
||||||
|
//#define POLARSSL_FS_IO
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_NO_DEFAULT_ENTROPY_SOURCES
|
||||||
|
*
|
||||||
|
* Do not add default entropy sources. These are the platform specific,
|
||||||
|
* hardclock and HAVEGE based poll functions.
|
||||||
|
*
|
||||||
|
* This is useful to have more control over the added entropy sources in an
|
||||||
|
* application.
|
||||||
|
*
|
||||||
|
* Uncomment this macro to prevent loading of default entropy functions.
|
||||||
|
#define POLARSSL_NO_DEFAULT_ENTROPY_SOURCES
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_NO_PLATFORM_ENTROPY
|
||||||
|
*
|
||||||
|
* Do not use built-in platform entropy functions.
|
||||||
|
* This is useful if your platform does not support
|
||||||
|
* standards like the /dev/urandom or Windows CryptoAPI.
|
||||||
|
*
|
||||||
|
* Uncomment this macro to disable the built-in platform entropy functions.
|
||||||
|
#define POLARSSL_NO_PLATFORM_ENTROPY
|
||||||
|
*/
|
||||||
|
|
||||||
|
// JY added
|
||||||
|
#ifdef EXTERNAL_RNG
|
||||||
|
#define POLARSSL_NO_DEFAULT_ENTROPY_SOURCES
|
||||||
|
#define POLARSSL_NO_PLATFORM_ENTROPY
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_PKCS1_V21
|
||||||
|
*
|
||||||
|
* Requires: POLARSSL_MD_C, POLARSSL_RSA_C
|
||||||
|
*
|
||||||
|
* Enable support for PKCS#1 v2.1 encoding.
|
||||||
|
* This enables support for RSAES-OAEP and RSASSA-PSS operations.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_PKCS1_V21
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_RSA_NO_CRT
|
||||||
|
*
|
||||||
|
* Do not use the Chinese Remainder Theorem for the RSA private operation.
|
||||||
|
*
|
||||||
|
* Uncomment this macro to disable the use of CRT in RSA.
|
||||||
|
*
|
||||||
|
#define POLARSSL_RSA_NO_CRT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_SELF_TEST
|
||||||
|
*
|
||||||
|
* Enable the checkup functions (*_self_test).
|
||||||
|
*/
|
||||||
|
// JY changed
|
||||||
|
#if defined(ENABLE_TESTING) && !defined(POLARSSL_SELF_TEST)
|
||||||
|
#define POLARSSL_SELF_TEST
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_SSL_ALL_ALERT_MESSAGES
|
||||||
|
*
|
||||||
|
* Enable sending of alert messages in case of encountered errors as per RFC.
|
||||||
|
* If you choose not to send the alert messages, PolarSSL can still communicate
|
||||||
|
* with other servers, only debugging of failures is harder.
|
||||||
|
*
|
||||||
|
* The advantage of not sending alert messages, is that no information is given
|
||||||
|
* about reasons for failures thus preventing adversaries of gaining intel.
|
||||||
|
*
|
||||||
|
* Enable sending of all alert messages
|
||||||
|
*/
|
||||||
|
#define POLARSSL_SSL_ALERT_MESSAGES
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_SSL_DEBUG_ALL
|
||||||
|
*
|
||||||
|
* Enable the debug messages in SSL module for all issues.
|
||||||
|
* Debug messages have been disabled in some places to prevent timing
|
||||||
|
* attacks due to (unbalanced) debugging function calls.
|
||||||
|
*
|
||||||
|
* If you need all error reporting you should enable this during debugging,
|
||||||
|
* but remove this for production servers that should log as well.
|
||||||
|
*
|
||||||
|
* Uncomment this macro to report all debug messages on errors introducing
|
||||||
|
* a timing side-channel.
|
||||||
|
*
|
||||||
|
#define POLARSSL_SSL_DEBUG_ALL
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_SSL_HW_RECORD_ACCEL
|
||||||
|
*
|
||||||
|
* Enable hooking functions in SSL module for hardware acceleration of
|
||||||
|
* individual records.
|
||||||
|
*
|
||||||
|
* Uncomment this macro to enable hooking functions.
|
||||||
|
#define POLARSSL_SSL_HW_RECORD_ACCEL
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO
|
||||||
|
*
|
||||||
|
* Enable support for receiving and parsing SSLv2 Client Hello messages for the
|
||||||
|
* SSL Server module (POLARSSL_SSL_SRV_C)
|
||||||
|
*
|
||||||
|
* Comment this macro to disable support for SSLv2 Client Hello messages.
|
||||||
|
*/
|
||||||
|
// JY removed
|
||||||
|
//#define POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
|
||||||
|
*
|
||||||
|
* If set, the X509 parser will not break-off when parsing an X509 certificate
|
||||||
|
* and encountering an unknown critical extension.
|
||||||
|
*
|
||||||
|
* Uncomment to prevent an error.
|
||||||
|
*
|
||||||
|
#define POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_ZLIB_SUPPORT
|
||||||
|
*
|
||||||
|
* If set, the SSL/TLS module uses ZLIB to support compression and
|
||||||
|
* decompression of packet data.
|
||||||
|
*
|
||||||
|
* Used in: library/ssl_tls.c
|
||||||
|
* library/ssl_cli.c
|
||||||
|
* library/ssl_srv.c
|
||||||
|
*
|
||||||
|
* This feature requires zlib library and headers to be present.
|
||||||
|
*
|
||||||
|
* Uncomment to enable use of ZLIB
|
||||||
|
#define POLARSSL_ZLIB_SUPPORT
|
||||||
|
*/
|
||||||
|
/* \} name */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \name SECTION: PolarSSL modules
|
||||||
|
*
|
||||||
|
* This section enables or disables entire modules in PolarSSL
|
||||||
|
* \{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_AES_C
|
||||||
|
*
|
||||||
|
* Enable the AES block cipher.
|
||||||
|
*
|
||||||
|
* Module: library/aes.c
|
||||||
|
* Caller: library/ssl_tls.c
|
||||||
|
* library/pem.c
|
||||||
|
* library/ctr_drbg.c
|
||||||
|
*
|
||||||
|
* This module enables the following ciphersuites (if other requisites are
|
||||||
|
* enabled as well):
|
||||||
|
* TLS_RSA_WITH_AES_128_CBC_SHA
|
||||||
|
* TLS_RSA_WITH_AES_256_CBC_SHA
|
||||||
|
* TLS_DHE_RSA_WITH_AES_128_CBC_SHA
|
||||||
|
* TLS_DHE_RSA_WITH_AES_256_CBC_SHA
|
||||||
|
* TLS_RSA_WITH_AES_128_CBC_SHA256
|
||||||
|
* TLS_RSA_WITH_AES_256_CBC_SHA256
|
||||||
|
* TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
|
||||||
|
* TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
|
||||||
|
* TLS_RSA_WITH_AES_128_GCM_SHA256
|
||||||
|
* TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||||
|
*
|
||||||
|
* PEM uses AES for decrypting encrypted keys.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_AES_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_ARC4_C
|
||||||
|
*
|
||||||
|
* Enable the ARCFOUR stream cipher.
|
||||||
|
*
|
||||||
|
* Module: library/arc4.c
|
||||||
|
* Caller: library/ssl_tls.c
|
||||||
|
*
|
||||||
|
* This module enables the following ciphersuites:
|
||||||
|
* TLS_RSA_WITH_RC4_128_MD5
|
||||||
|
* TLS_RSA_WITH_RC4_128_SHA
|
||||||
|
*/
|
||||||
|
// JY removed
|
||||||
|
//#define POLARSSL_ARC4_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_ASN1_PARSE_C
|
||||||
|
*
|
||||||
|
* Enable the generic ASN1 parser.
|
||||||
|
*
|
||||||
|
* Module: library/asn1.c
|
||||||
|
* Caller: library/x509parse.c
|
||||||
|
*/
|
||||||
|
#define POLARSSL_ASN1_PARSE_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_ASN1_WRITE_C
|
||||||
|
*
|
||||||
|
* Enable the generic ASN1 writer.
|
||||||
|
*
|
||||||
|
* Module: library/asn1write.c
|
||||||
|
*/
|
||||||
|
// JY removed
|
||||||
|
//#define POLARSSL_ASN1_WRITE_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_BASE64_C
|
||||||
|
*
|
||||||
|
* Enable the Base64 module.
|
||||||
|
*
|
||||||
|
* Module: library/base64.c
|
||||||
|
* Caller: library/pem.c
|
||||||
|
*
|
||||||
|
* This module is required for PEM support (required by X.509).
|
||||||
|
*/
|
||||||
|
#define POLARSSL_BASE64_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_BIGNUM_C
|
||||||
|
*
|
||||||
|
* Enable the multi-precision integer library.
|
||||||
|
*
|
||||||
|
* Module: library/bignum.c
|
||||||
|
* Caller: library/dhm.c
|
||||||
|
* library/rsa.c
|
||||||
|
* library/ssl_tls.c
|
||||||
|
* library/x509parse.c
|
||||||
|
*
|
||||||
|
* This module is required for RSA and DHM support.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_BIGNUM_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_BLOWFISH_C
|
||||||
|
*
|
||||||
|
* Enable the Blowfish block cipher.
|
||||||
|
*
|
||||||
|
* Module: library/blowfish.c
|
||||||
|
*/
|
||||||
|
#define POLARSSL_BLOWFISH_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_CAMELLIA_C
|
||||||
|
*
|
||||||
|
* Enable the Camellia block cipher.
|
||||||
|
*
|
||||||
|
* Module: library/camellia.c
|
||||||
|
* Caller: library/ssl_tls.c
|
||||||
|
*
|
||||||
|
* This module enables the following ciphersuites (if other requisites are
|
||||||
|
* enabled as well):
|
||||||
|
* TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
|
||||||
|
* TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
|
||||||
|
* TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
|
||||||
|
* TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
|
||||||
|
* TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
|
||||||
|
* TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
|
||||||
|
* TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
|
||||||
|
* TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
|
||||||
|
*/
|
||||||
|
// JY removed
|
||||||
|
//#define POLARSSL_CAMELLIA_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_CERTS_C
|
||||||
|
*
|
||||||
|
* Enable the test certificates.
|
||||||
|
*
|
||||||
|
* Module: library/certs.c
|
||||||
|
* Caller:
|
||||||
|
*
|
||||||
|
* This module is used for testing (ssl_client/server).
|
||||||
|
*/
|
||||||
|
// JY changed
|
||||||
|
#ifdef ENABLE_TESTING
|
||||||
|
#define POLARSSL_CERTS_C
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_CIPHER_C
|
||||||
|
*
|
||||||
|
* Enable the generic cipher layer.
|
||||||
|
*
|
||||||
|
* Module: library/cipher.c
|
||||||
|
* Caller:
|
||||||
|
*
|
||||||
|
* Uncomment to enable generic cipher wrappers.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_CIPHER_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_CTR_DRBG_C
|
||||||
|
*
|
||||||
|
* Enable the CTR_DRBG AES-256-based random generator
|
||||||
|
*
|
||||||
|
* Module: library/ctr_drbg.c
|
||||||
|
* Caller:
|
||||||
|
*
|
||||||
|
* Requires: POLARSSL_AES_C
|
||||||
|
*
|
||||||
|
* This module provides the CTR_DRBG AES-256 random number generator.
|
||||||
|
*/
|
||||||
|
// JY added
|
||||||
|
#ifndef EXTERNAL_RNG
|
||||||
|
#define POLARSSL_CTR_DRBG_C
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_DEBUG_C
|
||||||
|
*
|
||||||
|
* Enable the debug functions.
|
||||||
|
*
|
||||||
|
* Module: library/debug.c
|
||||||
|
* Caller: library/ssl_cli.c
|
||||||
|
* library/ssl_srv.c
|
||||||
|
* library/ssl_tls.c
|
||||||
|
*
|
||||||
|
* This module provides debugging functions.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_DEBUG_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_DES_C
|
||||||
|
*
|
||||||
|
* Enable the DES block cipher.
|
||||||
|
*
|
||||||
|
* Module: library/des.c
|
||||||
|
* Caller: library/pem.c
|
||||||
|
* library/ssl_tls.c
|
||||||
|
*
|
||||||
|
* This module enables the following ciphersuites (if other requisites are
|
||||||
|
* enabled as well):
|
||||||
|
* TLS_RSA_WITH_3DES_EDE_CBC_SHA
|
||||||
|
* TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
|
||||||
|
*
|
||||||
|
* PEM uses DES/3DES for decrypting encrypted keys.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_DES_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_DHM_C
|
||||||
|
*
|
||||||
|
* Enable the Diffie-Hellman-Merkle key exchange.
|
||||||
|
*
|
||||||
|
* Module: library/dhm.c
|
||||||
|
* Caller: library/ssl_cli.c
|
||||||
|
* library/ssl_srv.c
|
||||||
|
*
|
||||||
|
* This module enables the following ciphersuites (if other requisites are
|
||||||
|
* enabled as well):
|
||||||
|
* TLS_DHE_RSA_WITH_DES_CBC_SHA
|
||||||
|
* TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
|
||||||
|
* TLS_DHE_RSA_WITH_AES_128_CBC_SHA
|
||||||
|
* TLS_DHE_RSA_WITH_AES_256_CBC_SHA
|
||||||
|
* TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
|
||||||
|
* TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
|
||||||
|
* TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
|
||||||
|
* TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
|
||||||
|
* TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
|
||||||
|
* TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
|
||||||
|
* TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
|
||||||
|
* TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
|
||||||
|
*/
|
||||||
|
#define POLARSSL_DHM_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_ENTROPY_C
|
||||||
|
*
|
||||||
|
* Enable the platform-specific entropy code.
|
||||||
|
*
|
||||||
|
* Module: library/entropy.c
|
||||||
|
* Caller:
|
||||||
|
*
|
||||||
|
* Requires: POLARSSL_SHA4_C
|
||||||
|
*
|
||||||
|
* This module provides a generic entropy pool
|
||||||
|
*/
|
||||||
|
#define POLARSSL_ENTROPY_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_ERROR_C
|
||||||
|
*
|
||||||
|
* Enable error code to error string conversion.
|
||||||
|
*
|
||||||
|
* Module: library/error.c
|
||||||
|
* Caller:
|
||||||
|
*
|
||||||
|
* This module enables err_strerror().
|
||||||
|
*/
|
||||||
|
#define POLARSSL_ERROR_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_GCM_C
|
||||||
|
*
|
||||||
|
* Enable the Galois/Counter Mode (GCM) for AES
|
||||||
|
*
|
||||||
|
* Module: library/gcm.c
|
||||||
|
*
|
||||||
|
* Requires: POLARSSL_AES_C
|
||||||
|
*
|
||||||
|
* This module enables the following ciphersuites (if other requisites are
|
||||||
|
* enabled as well):
|
||||||
|
* TLS_RSA_WITH_AES_128_GCM_SHA256
|
||||||
|
* TLS_RSA_WITH_AES_256_GCM_SHA384
|
||||||
|
*/
|
||||||
|
#define POLARSSL_GCM_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_HAVEGE_C
|
||||||
|
*
|
||||||
|
* Enable the HAVEGE random generator.
|
||||||
|
*
|
||||||
|
* Module: library/havege.c
|
||||||
|
* Caller:
|
||||||
|
*
|
||||||
|
* Requires: POLARSSL_TIMING_C
|
||||||
|
*
|
||||||
|
* This module enables the HAVEGE random number generator.
|
||||||
|
*/
|
||||||
|
// JY removed
|
||||||
|
//#define POLARSSL_HAVEGE_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_MD_C
|
||||||
|
*
|
||||||
|
* Enable the generic message digest layer.
|
||||||
|
*
|
||||||
|
* Module: library/md.c
|
||||||
|
* Caller:
|
||||||
|
*
|
||||||
|
* Uncomment to enable generic message digest wrappers.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_MD_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_MD2_C
|
||||||
|
*
|
||||||
|
* Enable the MD2 hash algorithm
|
||||||
|
*
|
||||||
|
* Module: library/md2.c
|
||||||
|
* Caller: library/x509parse.c
|
||||||
|
*
|
||||||
|
* Uncomment to enable support for (rare) MD2-signed X.509 certs.
|
||||||
|
*
|
||||||
|
#define POLARSSL_MD2_C
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_MD4_C
|
||||||
|
*
|
||||||
|
* Enable the MD4 hash algorithm
|
||||||
|
*
|
||||||
|
* Module: library/md4.c
|
||||||
|
* Caller: library/x509parse.c
|
||||||
|
*
|
||||||
|
* Uncomment to enable support for (rare) MD4-signed X.509 certs.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
// JY Added for NTLM proxy auth
|
||||||
|
#define POLARSSL_MD4_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_MD5_C
|
||||||
|
*
|
||||||
|
* Enable the MD5 hash algorithm
|
||||||
|
*
|
||||||
|
* Module: library/md5.c
|
||||||
|
* Caller: library/pem.c
|
||||||
|
* library/ssl_tls.c
|
||||||
|
* library/x509parse.c
|
||||||
|
*
|
||||||
|
* This module is required for SSL/TLS and X.509.
|
||||||
|
* PEM uses MD5 for decrypting encrypted keys.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_MD5_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_NET_C
|
||||||
|
*
|
||||||
|
* Enable the TCP/IP networking routines.
|
||||||
|
*
|
||||||
|
* Module: library/net.c
|
||||||
|
* Caller:
|
||||||
|
*
|
||||||
|
* This module provides TCP/IP networking routines.
|
||||||
|
*/
|
||||||
|
// JY removed
|
||||||
|
//#define POLARSSL_NET_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_PADLOCK_C
|
||||||
|
*
|
||||||
|
* Enable VIA Padlock support on x86.
|
||||||
|
*
|
||||||
|
* Module: library/padlock.c
|
||||||
|
* Caller: library/aes.c
|
||||||
|
*
|
||||||
|
* This modules adds support for the VIA PadLock on x86.
|
||||||
|
*/
|
||||||
|
// JY removed
|
||||||
|
//#define POLARSSL_PADLOCK_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_PBKDF2_C
|
||||||
|
*
|
||||||
|
* Enable PKCS#5 PBKDF2 key derivation function
|
||||||
|
* DEPRECATED: Use POLARSSL_PKCS5_C instead
|
||||||
|
*
|
||||||
|
* Module: library/pbkdf2.c
|
||||||
|
*
|
||||||
|
* Requires: POLARSSL_PKCS5_C
|
||||||
|
*
|
||||||
|
* This module adds support for the PKCS#5 PBKDF2 key derivation function.
|
||||||
|
#define POLARSSL_PBKDF2_C
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_PEM_C
|
||||||
|
*
|
||||||
|
* Enable PEM decoding
|
||||||
|
*
|
||||||
|
* Module: library/pem.c
|
||||||
|
* Caller: library/x509parse.c
|
||||||
|
*
|
||||||
|
* Requires: POLARSSL_BASE64_C
|
||||||
|
*
|
||||||
|
* This modules adds support for decoding PEM files.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_PEM_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_PKCS5_C
|
||||||
|
*
|
||||||
|
* Enable PKCS#5 functions
|
||||||
|
*
|
||||||
|
* Module: library/pkcs5.c
|
||||||
|
*
|
||||||
|
* Requires: POLARSSL_MD_C
|
||||||
|
*
|
||||||
|
* This module adds support for the PKCS#5 functions.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_PKCS5_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_PKCS11_C
|
||||||
|
*
|
||||||
|
* Enable wrapper for PKCS#11 smartcard support.
|
||||||
|
*
|
||||||
|
* Module: library/ssl_srv.c
|
||||||
|
* Caller: library/ssl_cli.c
|
||||||
|
* library/ssl_srv.c
|
||||||
|
*
|
||||||
|
* Requires: POLARSSL_SSL_TLS_C
|
||||||
|
*
|
||||||
|
* This module enables SSL/TLS PKCS #11 smartcard support.
|
||||||
|
* Requires the presence of the PKCS#11 helper library (libpkcs11-helper)
|
||||||
|
#define POLARSSL_PKCS11_C
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_PKCS12_C
|
||||||
|
*
|
||||||
|
* Enable PKCS#12 PBE functions
|
||||||
|
* Adds algorithms for parsing PKCS#8 encrypted private keys
|
||||||
|
*
|
||||||
|
* Module: library/pkcs12.c
|
||||||
|
* Caller: library/x509parse.c
|
||||||
|
*
|
||||||
|
* Requires: POLARSSL_ASN1_PARSE_C
|
||||||
|
* Can use: POLARSSL_SHA1_C, POLARSSL_DES_C, POLARSSL_ARC4_C
|
||||||
|
*
|
||||||
|
* This module enables PKCS#12 functions.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_PKCS12_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_RSA_C
|
||||||
|
*
|
||||||
|
* Enable the RSA public-key cryptosystem.
|
||||||
|
*
|
||||||
|
* Module: library/rsa.c
|
||||||
|
* Caller: library/ssl_cli.c
|
||||||
|
* library/ssl_srv.c
|
||||||
|
* library/ssl_tls.c
|
||||||
|
* library/x509.c
|
||||||
|
*
|
||||||
|
* Requires: POLARSSL_BIGNUM_C
|
||||||
|
*
|
||||||
|
* This module is required for SSL/TLS and MD5-signed certificates.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_RSA_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_SHA1_C
|
||||||
|
*
|
||||||
|
* Enable the SHA1 cryptographic hash algorithm.
|
||||||
|
*
|
||||||
|
* Module: library/sha1.c
|
||||||
|
* Caller: library/ssl_cli.c
|
||||||
|
* library/ssl_srv.c
|
||||||
|
* library/ssl_tls.c
|
||||||
|
* library/x509parse.c
|
||||||
|
*
|
||||||
|
* This module is required for SSL/TLS and SHA1-signed certificates.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_SHA1_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_SHA2_C
|
||||||
|
*
|
||||||
|
* Enable the SHA-224 and SHA-256 cryptographic hash algorithms.
|
||||||
|
*
|
||||||
|
* Module: library/sha2.c
|
||||||
|
* Caller: library/md_wrap.c
|
||||||
|
* library/x509parse.c
|
||||||
|
*
|
||||||
|
* This module adds support for SHA-224 and SHA-256.
|
||||||
|
* This module is required for the SSL/TLS 1.2 PRF function.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_SHA2_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_SHA4_C
|
||||||
|
*
|
||||||
|
* Enable the SHA-384 and SHA-512 cryptographic hash algorithms.
|
||||||
|
*
|
||||||
|
* Module: library/sha4.c
|
||||||
|
* Caller: library/md_wrap.c
|
||||||
|
* library/x509parse.c
|
||||||
|
*
|
||||||
|
* This module adds support for SHA-384 and SHA-512.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_SHA4_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_SSL_CACHE_C
|
||||||
|
*
|
||||||
|
* Enable simple SSL cache implementation.
|
||||||
|
*
|
||||||
|
* Module: library/ssl_cache.c
|
||||||
|
* Caller:
|
||||||
|
*
|
||||||
|
* Requires: POLARSSL_SSL_CACHE_C
|
||||||
|
*/
|
||||||
|
// JY removed
|
||||||
|
//#define POLARSSL_SSL_CACHE_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_SSL_CLI_C
|
||||||
|
*
|
||||||
|
* Enable the SSL/TLS client code.
|
||||||
|
*
|
||||||
|
* Module: library/ssl_cli.c
|
||||||
|
* Caller:
|
||||||
|
*
|
||||||
|
* Requires: POLARSSL_SSL_TLS_C
|
||||||
|
*
|
||||||
|
* This module is required for SSL/TLS client support.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_SSL_CLI_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_SSL_SRV_C
|
||||||
|
*
|
||||||
|
* Enable the SSL/TLS server code.
|
||||||
|
*
|
||||||
|
* Module: library/ssl_srv.c
|
||||||
|
* Caller:
|
||||||
|
*
|
||||||
|
* Requires: POLARSSL_SSL_TLS_C
|
||||||
|
*
|
||||||
|
* This module is required for SSL/TLS server support.
|
||||||
|
*/
|
||||||
|
// JY removed
|
||||||
|
//#define POLARSSL_SSL_SRV_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_SSL_TLS_C
|
||||||
|
*
|
||||||
|
* Enable the generic SSL/TLS code.
|
||||||
|
*
|
||||||
|
* Module: library/ssl_tls.c
|
||||||
|
* Caller: library/ssl_cli.c
|
||||||
|
* library/ssl_srv.c
|
||||||
|
*
|
||||||
|
* Requires: POLARSSL_MD5_C, POLARSSL_SHA1_C, POLARSSL_X509_PARSE_C
|
||||||
|
*
|
||||||
|
* This module is required for SSL/TLS.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_SSL_TLS_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_TIMING_C
|
||||||
|
*
|
||||||
|
* Enable the portable timing interface.
|
||||||
|
*
|
||||||
|
* Module: library/timing.c
|
||||||
|
* Caller: library/havege.c
|
||||||
|
*
|
||||||
|
* This module is used by the HAVEGE random number generator.
|
||||||
|
*/
|
||||||
|
// JY removed
|
||||||
|
//#define POLARSSL_TIMING_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_VERSION_C
|
||||||
|
*
|
||||||
|
* Enable run-time version information.
|
||||||
|
*
|
||||||
|
* Module: library/version.c
|
||||||
|
*
|
||||||
|
* This module provides run-time version information.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_VERSION_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_X509_PARSE_C
|
||||||
|
*
|
||||||
|
* Enable X.509 certificate parsing.
|
||||||
|
*
|
||||||
|
* Module: library/x509parse.c
|
||||||
|
* Caller: library/ssl_cli.c
|
||||||
|
* library/ssl_srv.c
|
||||||
|
* library/ssl_tls.c
|
||||||
|
*
|
||||||
|
* Requires: POLARSSL_ASN1_PARSE_C, POLARSSL_BIGNUM_C, POLARSSL_RSA_C
|
||||||
|
*
|
||||||
|
* This module is required for X.509 certificate parsing.
|
||||||
|
*/
|
||||||
|
#define POLARSSL_X509_PARSE_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_X509_WRITE_C
|
||||||
|
*
|
||||||
|
* Enable X.509 buffer writing.
|
||||||
|
*
|
||||||
|
* Module: library/x509write.c
|
||||||
|
*
|
||||||
|
* Requires: POLARSSL_BIGNUM_C, POLARSSL_RSA_C
|
||||||
|
*
|
||||||
|
* This module is required for X.509 certificate request writing.
|
||||||
|
*/
|
||||||
|
// JY removed
|
||||||
|
//#define POLARSSL_X509_WRITE_C
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \def POLARSSL_XTEA_C
|
||||||
|
*
|
||||||
|
* Enable the XTEA block cipher.
|
||||||
|
*
|
||||||
|
* Module: library/xtea.c
|
||||||
|
* Caller:
|
||||||
|
*/
|
||||||
|
// JY removed
|
||||||
|
//#define POLARSSL_XTEA_C
|
||||||
|
/* \} name */
|
||||||
|
|
||||||
|
// JY added
|
||||||
|
#define POLARSSL_BLOWFISH_NAME "BF"
|
||||||
|
#define POLARSSL_BLOWFISH_DEFAULT_KEY_LEN 128
|
||||||
|
|
||||||
|
#endif /* config.h */
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
This patch (against PolarSSL 1.2.7) allows alternative crypto
|
||||||
|
implementations to be compiled, without actually defining
|
||||||
|
such implementations.
|
||||||
|
|
||||||
|
* define POLARSSL_AES_ALT to include alternative AES implementation
|
||||||
|
from polarssl/aes_alt.h
|
||||||
|
|
||||||
|
* define POLARSSL_SHA1_ALT to include alternative SHA1 implementation
|
||||||
|
from polarssl/sha1_alt.h
|
||||||
|
|
||||||
|
* define POLARSSL_SHA2_ALT to include alternative SHA2 implementation
|
||||||
|
from polarssl/sha2_alt.h
|
||||||
|
|
||||||
|
* define POLARSSL_SHA4_ALT to include alternative SHA4 implementation
|
||||||
|
from polarssl/sha4_alt.h
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
diff -ur polarssl-1.3.4/library/dhm.c polarssl.new/library/dhm.c
|
||||||
|
--- polarssl-1.3.4/library/dhm.c 2014-01-27 05:36:23.000000000 -0700
|
||||||
|
+++ polarssl.new/library/dhm.c 2014-03-02 14:47:02.000000000 -0700
|
||||||
|
@@ -32,6 +32,8 @@
|
||||||
|
|
||||||
|
#if defined(POLARSSL_DHM_C)
|
||||||
|
|
||||||
|
+#include "polarssl/x509.h" // for POLARSSL_ERR_X509_FEATURE_UNAVAILABLE
|
||||||
|
+
|
||||||
|
#include "polarssl/dhm.h"
|
||||||
|
|
||||||
|
#if defined(POLARSSL_PEM_PARSE_C)
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
diff -ur polarssl-1.3.8.orig/library/entropy.c polarssl-1.3.8/library/entropy.c
|
||||||
|
--- polarssl-1.3.8.orig/library/entropy.c 2014-07-09 03:34:48.000000000 -0600
|
||||||
|
+++ polarssl-1.3.8/library/entropy.c 2014-07-09 16:27:06.000000000 -0600
|
||||||
|
@@ -34,7 +34,7 @@
|
||||||
|
#include "polarssl/entropy.h"
|
||||||
|
#include "polarssl/entropy_poll.h"
|
||||||
|
|
||||||
|
-#if defined(POLARSSL_FS_IO)
|
||||||
|
+#if defined(POLARSSL_FS_IO) || defined(POLARSSL_SELF_TEST)
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
. $O3/core/deps/lib-versions
|
||||||
|
rm -rf gitar.tmp
|
||||||
|
mkdir gitar.tmp
|
||||||
|
cd gitar.tmp
|
||||||
|
git clone https://github.com/polarssl/polarssl.git -b $POLARSSL_VERSION $POLARSSL_VERSION
|
||||||
|
tar cfz $DL/$POLARSSL_VERSION-gpl.tgz $POLARSSL_VERSION
|
||||||
|
cd ..
|
||||||
|
rm -rf gitar.tmp
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#if defined(_WIN32)
|
||||||
|
typedef unsigned __int64 IA32CAP;
|
||||||
|
#else
|
||||||
|
typedef unsigned long long IA32CAP;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
IA32CAP OPENSSL_ia32_cpuid(void);
|
||||||
|
|
||||||
|
unsigned int OPENSSL_ia32cap_P[2]; // GLOBAL
|
||||||
|
|
||||||
|
void OPENSSL_cpuid_setup(void)
|
||||||
|
{
|
||||||
|
const IA32CAP vec = OPENSSL_ia32_cpuid();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* |(1<<10) sets a reserved bit to signal that variable
|
||||||
|
* was initialized already... This is to avoid interference
|
||||||
|
* with cpuid snippets in ELF .init segment.
|
||||||
|
*/
|
||||||
|
OPENSSL_ia32cap_P[0] = (unsigned int)vec|(1<<10);
|
||||||
|
OPENSSL_ia32cap_P[1] = (unsigned int)(vec>>32);
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
# this one is important
|
||||||
|
SET(CMAKE_SYSTEM_NAME Linux)
|
||||||
|
#this one not so much
|
||||||
|
SET(CMAKE_SYSTEM_VERSION 1)
|
||||||
|
|
||||||
|
# specify the cross compiler
|
||||||
|
SET(CMAKE_C_COMPILER arm-linux-gnueabi-gcc-4.6)
|
||||||
|
SET(CMAKE_CXX_COMPILER arm-linux-gnueabi-g++-4.6)
|
||||||
|
|
||||||
|
# where is the target environment
|
||||||
|
#SET(CMAKE_FIND_ROOT_PATH /opt/eldk-2007-01-19/ppc_74xx /home/alex/eldk-ppc74xx-inst)
|
||||||
|
|
||||||
|
# search for programs in the build host directories
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||||
|
# for libraries and headers in the target directories
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||||
|
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||||
@@ -0,0 +1,782 @@
|
|||||||
|
diff -uNr polarssl-1.2.7/include/polarssl/aes.h polarssl.new/include/polarssl/aes.h
|
||||||
|
--- polarssl-1.2.7/include/polarssl/aes.h 2013-04-13 03:56:17.000000000 -0600
|
||||||
|
+++ polarssl.new/include/polarssl/aes.h 2013-06-07 17:43:56.000000000 -0600
|
||||||
|
@@ -29,6 +29,8 @@
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
+#include "config.h"
|
||||||
|
+
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <basetsd.h>
|
||||||
|
typedef UINT32 uint32_t;
|
||||||
|
@@ -42,6 +44,12 @@
|
||||||
|
#define POLARSSL_ERR_AES_INVALID_KEY_LENGTH -0x0020 /**< Invalid key length. */
|
||||||
|
#define POLARSSL_ERR_AES_INVALID_INPUT_LENGTH -0x0022 /**< Invalid data input length. */
|
||||||
|
|
||||||
|
+#ifdef POLARSSL_AES_ALT
|
||||||
|
+
|
||||||
|
+#include "polarssl/aes_alt.h"
|
||||||
|
+
|
||||||
|
+#else
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* \brief AES context structure
|
||||||
|
*/
|
||||||
|
@@ -169,6 +177,17 @@
|
||||||
|
unsigned char stream_block[16],
|
||||||
|
const unsigned char *input,
|
||||||
|
unsigned char *output );
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#endif /* POLARSSL_AES_ALT */
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+extern "C" {
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* \brief Checkup routine
|
||||||
|
*
|
||||||
|
diff -uNr polarssl-1.2.7/include/polarssl/aes_alt.h polarssl.new/include/polarssl/aes_alt.h
|
||||||
|
--- polarssl-1.2.7/include/polarssl/aes_alt.h 1969-12-31 17:00:00.000000000 -0700
|
||||||
|
+++ polarssl.new/include/polarssl/aes_alt.h 2013-06-07 18:18:37.000000000 -0600
|
||||||
|
@@ -0,0 +1,183 @@
|
||||||
|
+/*
|
||||||
|
+ * Use OpenSSL implementation of AES methods to get asm and hardware acceleration.
|
||||||
|
+ * Don't include this file directly, it is included by aes.h when
|
||||||
|
+ * POLARSSL_AES_ALT is defined.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#ifdef _MSC_VER
|
||||||
|
+#include <basetsd.h>
|
||||||
|
+typedef UINT32 uint32_t;
|
||||||
|
+#else
|
||||||
|
+#include <inttypes.h>
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#define OPENSSL_AES_BLOCK_SIZE 16
|
||||||
|
+#define OPENSSL_AES_MAXNR 14
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * \brief AES context structure
|
||||||
|
+ */
|
||||||
|
+typedef struct
|
||||||
|
+{
|
||||||
|
+ uint32_t rd_key[4 * (OPENSSL_AES_MAXNR + 1)];
|
||||||
|
+ int rounds;
|
||||||
|
+}
|
||||||
|
+aes_context;
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+extern "C" {
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#if defined(POLARSSL_USE_OPENSSL_AES_NI)
|
||||||
|
+
|
||||||
|
+int aesni_set_encrypt_key(const unsigned char *userKey, const int bits,
|
||||||
|
+ aes_context *key);
|
||||||
|
+int aesni_set_decrypt_key(const unsigned char *userKey, const int bits,
|
||||||
|
+ aes_context *key);
|
||||||
|
+void aesni_ecb_encrypt(const unsigned char *in, unsigned char *out,
|
||||||
|
+ size_t length, const aes_context *key, const int enc);
|
||||||
|
+void aesni_cbc_encrypt(const unsigned char *in, unsigned char *out,
|
||||||
|
+ size_t length, const aes_context *key,
|
||||||
|
+ unsigned char *ivec, const int enc);
|
||||||
|
+
|
||||||
|
+#define OPENSSL_AES_SET_ENCRYPT_KEY(k,b,c) aesni_set_encrypt_key(k,b,c)
|
||||||
|
+#define OPENSSL_AES_SET_DECRYPT_KEY(k,b,c) aesni_set_decrypt_key(k,b,c)
|
||||||
|
+#define OPENSSL_AES_ECB_ENCRYPT(i,o,k) aesni_ecb_encrypt(i,o,16,k,AES_ENCRYPT)
|
||||||
|
+#define OPENSSL_AES_ECB_DECRYPT(i,o,k) aesni_ecb_encrypt(i,o,16,k,AES_DECRYPT)
|
||||||
|
+#define OPENSSL_AES_CBC_ENCRYPT(i,o,l,k,iv,e) aesni_cbc_encrypt(i,o,l,k,iv,e)
|
||||||
|
+
|
||||||
|
+#else
|
||||||
|
+
|
||||||
|
+int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
|
||||||
|
+ aes_context *key);
|
||||||
|
+int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
|
||||||
|
+ aes_context *key);
|
||||||
|
+
|
||||||
|
+void AES_encrypt(const unsigned char *in, unsigned char *out, const aes_context *key);
|
||||||
|
+void AES_decrypt(const unsigned char *in, unsigned char *out, const aes_context *key);
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+#define OPENSSL_AES_SET_ENCRYPT_KEY(k,b,c) AES_set_encrypt_key(k,b,c)
|
||||||
|
+#define OPENSSL_AES_SET_DECRYPT_KEY(k,b,c) AES_set_decrypt_key(k,b,c)
|
||||||
|
+#define OPENSSL_AES_ECB_ENCRYPT(i,o,k) AES_encrypt(i,o,k)
|
||||||
|
+#define OPENSSL_AES_ECB_DECRYPT(i,o,k) AES_decrypt(i,o,k)
|
||||||
|
+
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * \brief AES key schedule (encryption)
|
||||||
|
+ *
|
||||||
|
+ * \param ctx AES context to be initialized
|
||||||
|
+ * \param key encryption key
|
||||||
|
+ * \param keysize must be 128, 192 or 256
|
||||||
|
+ *
|
||||||
|
+ * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH
|
||||||
|
+ */
|
||||||
|
+static inline int aes_setkey_enc( aes_context *ctx, const unsigned char *key, const unsigned int keysize )
|
||||||
|
+{
|
||||||
|
+ const int status = OPENSSL_AES_SET_ENCRYPT_KEY(key, keysize, ctx);
|
||||||
|
+ return status ? POLARSSL_ERR_AES_INVALID_KEY_LENGTH : 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * \brief AES key schedule (decryption)
|
||||||
|
+ *
|
||||||
|
+ * \param ctx AES context to be initialized
|
||||||
|
+ * \param key decryption key
|
||||||
|
+ * \param keysize must be 128, 192 or 256
|
||||||
|
+ *
|
||||||
|
+ * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH
|
||||||
|
+ */
|
||||||
|
+static inline int aes_setkey_dec( aes_context *ctx, const unsigned char *key, const unsigned int keysize )
|
||||||
|
+{
|
||||||
|
+ const int status = OPENSSL_AES_SET_DECRYPT_KEY(key, keysize, ctx);
|
||||||
|
+ return status ? POLARSSL_ERR_AES_INVALID_KEY_LENGTH : 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * \brief AES-ECB block encryption/decryption
|
||||||
|
+ *
|
||||||
|
+ * \param ctx AES context
|
||||||
|
+ * \param mode AES_ENCRYPT or AES_DECRYPT
|
||||||
|
+ * \param input 16-byte input block
|
||||||
|
+ * \param output 16-byte output block
|
||||||
|
+ *
|
||||||
|
+ * \return 0 if successful
|
||||||
|
+ */
|
||||||
|
+static inline int aes_crypt_ecb( aes_context *ctx,
|
||||||
|
+ const int mode,
|
||||||
|
+ const unsigned char input[16],
|
||||||
|
+ unsigned char output[16] )
|
||||||
|
+{
|
||||||
|
+ if (mode == AES_DECRYPT)
|
||||||
|
+ OPENSSL_AES_ECB_DECRYPT(input, output, ctx);
|
||||||
|
+ else
|
||||||
|
+ OPENSSL_AES_ECB_ENCRYPT(input, output, ctx);
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * \brief AES-CBC buffer encryption/decryption
|
||||||
|
+ * Length should be a multiple of the block
|
||||||
|
+ * size (16 bytes)
|
||||||
|
+ *
|
||||||
|
+ * \param ctx AES context
|
||||||
|
+ * \param mode AES_ENCRYPT or AES_DECRYPT
|
||||||
|
+ * \param length length of the input data
|
||||||
|
+ * \param iv initialization vector (updated after use)
|
||||||
|
+ * \param input buffer holding the input data
|
||||||
|
+ * \param output buffer holding the output data
|
||||||
|
+ *
|
||||||
|
+ * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_INPUT_LENGTH
|
||||||
|
+ */
|
||||||
|
+static inline int aes_crypt_cbc( aes_context *ctx,
|
||||||
|
+ const int mode,
|
||||||
|
+ size_t length,
|
||||||
|
+ unsigned char iv[16],
|
||||||
|
+ const unsigned char *input,
|
||||||
|
+ unsigned char *output )
|
||||||
|
+{
|
||||||
|
+#ifdef OPENSSL_AES_CBC_ENCRYPT
|
||||||
|
+ if (length & (OPENSSL_AES_BLOCK_SIZE-1))
|
||||||
|
+ return POLARSSL_ERR_AES_INVALID_INPUT_LENGTH;
|
||||||
|
+ OPENSSL_AES_CBC_ENCRYPT(input, output, length, ctx, iv, mode);
|
||||||
|
+ return 0;
|
||||||
|
+#else
|
||||||
|
+ int i;
|
||||||
|
+ unsigned char temp[16];
|
||||||
|
+ if (length & (OPENSSL_AES_BLOCK_SIZE-1))
|
||||||
|
+ return POLARSSL_ERR_AES_INVALID_INPUT_LENGTH;
|
||||||
|
+ if( mode == AES_DECRYPT )
|
||||||
|
+ {
|
||||||
|
+ while( length > 0 )
|
||||||
|
+ {
|
||||||
|
+ memcpy( temp, input, 16 );
|
||||||
|
+ OPENSSL_AES_ECB_DECRYPT(input, output, ctx);
|
||||||
|
+ for( i = 0; i < 16; i++ )
|
||||||
|
+ output[i] = (unsigned char)( output[i] ^ iv[i] );
|
||||||
|
+ memcpy( iv, temp, 16 );
|
||||||
|
+ input += 16;
|
||||||
|
+ output += 16;
|
||||||
|
+ length -= 16;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+ while( length > 0 )
|
||||||
|
+ {
|
||||||
|
+ for( i = 0; i < 16; i++ )
|
||||||
|
+ output[i] = (unsigned char)( input[i] ^ iv[i] );
|
||||||
|
+ OPENSSL_AES_ECB_ENCRYPT(output, output, ctx);
|
||||||
|
+ memcpy( iv, output, 16 );
|
||||||
|
+ input += 16;
|
||||||
|
+ output += 16;
|
||||||
|
+ length -= 16;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return( 0 );
|
||||||
|
+#endif
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
diff -uNr polarssl-1.2.7/include/polarssl/sha1.h polarssl.new/include/polarssl/sha1.h
|
||||||
|
--- polarssl-1.2.7/include/polarssl/sha1.h 2013-04-13 03:56:17.000000000 -0600
|
||||||
|
+++ polarssl.new/include/polarssl/sha1.h 2013-06-07 17:43:56.000000000 -0600
|
||||||
|
@@ -29,6 +29,8 @@
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
+#include "config.h"
|
||||||
|
+
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <basetsd.h>
|
||||||
|
typedef UINT32 uint32_t;
|
||||||
|
@@ -38,6 +40,12 @@
|
||||||
|
|
||||||
|
#define POLARSSL_ERR_SHA1_FILE_IO_ERROR -0x0076 /**< Read/write error in file. */
|
||||||
|
|
||||||
|
+#ifdef POLARSSL_SHA1_ALT
|
||||||
|
+
|
||||||
|
+#include "polarssl/sha1_alt.h"
|
||||||
|
+
|
||||||
|
+#else
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* \brief SHA-1 context structure
|
||||||
|
*/
|
||||||
|
@@ -80,6 +88,19 @@
|
||||||
|
*/
|
||||||
|
void sha1_finish( sha1_context *ctx, unsigned char output[20] );
|
||||||
|
|
||||||
|
+/* Internal use */
|
||||||
|
+void sha1_process( sha1_context *ctx, const unsigned char data[64] );
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#endif /* POLARSSL_SHA1_ALT */
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+extern "C" {
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* \brief Output = SHA-1( input buffer )
|
||||||
|
*
|
||||||
|
@@ -152,9 +173,6 @@
|
||||||
|
*/
|
||||||
|
int sha1_self_test( int verbose );
|
||||||
|
|
||||||
|
-/* Internal use */
|
||||||
|
-void sha1_process( sha1_context *ctx, const unsigned char data[64] );
|
||||||
|
-
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
diff -uNr polarssl-1.2.7/include/polarssl/sha1_alt.h polarssl.new/include/polarssl/sha1_alt.h
|
||||||
|
--- polarssl-1.2.7/include/polarssl/sha1_alt.h 1969-12-31 17:00:00.000000000 -0700
|
||||||
|
+++ polarssl.new/include/polarssl/sha1_alt.h 2013-06-07 17:43:56.000000000 -0600
|
||||||
|
@@ -0,0 +1,56 @@
|
||||||
|
+/*
|
||||||
|
+ * Use OpenSSL implementation of SHA1 methods to get asm and hardware acceleration.
|
||||||
|
+ * Don't include this file directly, it is included by sha1.h when
|
||||||
|
+ * POLARSSL_SHA1_ALT is defined.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include "polarssl/sha_openssl.h"
|
||||||
|
+
|
||||||
|
+struct openssl_sha_context {
|
||||||
|
+ SHA_LONG h0,h1,h2,h3,h4;
|
||||||
|
+ SHA_LONG Nl,Nh;
|
||||||
|
+ SHA_LONG data[SHA_LBLOCK];
|
||||||
|
+ unsigned int num;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+typedef struct
|
||||||
|
+{
|
||||||
|
+ struct openssl_sha_context octx;
|
||||||
|
+
|
||||||
|
+ unsigned char ipad[64]; /*!< HMAC: inner padding */
|
||||||
|
+ unsigned char opad[64]; /*!< HMAC: outer padding */
|
||||||
|
+}
|
||||||
|
+sha1_context;
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+extern "C" {
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+int SHA1_Init(struct openssl_sha_context *c);
|
||||||
|
+int SHA1_Update(struct openssl_sha_context *c, const void *data, size_t len);
|
||||||
|
+int SHA1_Final(unsigned char *md, struct openssl_sha_context *c);
|
||||||
|
+void sha1_block_data_order(struct openssl_sha_context *c, const void *p, size_t num);
|
||||||
|
+
|
||||||
|
+static inline void sha1_starts( sha1_context *ctx )
|
||||||
|
+{
|
||||||
|
+ SHA1_Init(&ctx->octx);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void sha1_update( sha1_context *ctx, const unsigned char *input, size_t ilen )
|
||||||
|
+{
|
||||||
|
+ SHA1_Update(&ctx->octx, input, ilen);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void sha1_finish( sha1_context *ctx, unsigned char output[20] )
|
||||||
|
+{
|
||||||
|
+ SHA1_Final(output, &ctx->octx);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void sha1_process( sha1_context *ctx, const unsigned char data[64] )
|
||||||
|
+{
|
||||||
|
+ sha1_block_data_order(&ctx->octx, data, 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
diff -uNr polarssl-1.2.7/include/polarssl/sha2.h polarssl.new/include/polarssl/sha2.h
|
||||||
|
--- polarssl-1.2.7/include/polarssl/sha2.h 2013-04-13 03:56:17.000000000 -0600
|
||||||
|
+++ polarssl.new/include/polarssl/sha2.h 2013-06-07 17:43:56.000000000 -0600
|
||||||
|
@@ -29,6 +29,8 @@
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
+#include "config.h"
|
||||||
|
+
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#include <basetsd.h>
|
||||||
|
typedef UINT32 uint32_t;
|
||||||
|
@@ -38,6 +40,12 @@
|
||||||
|
|
||||||
|
#define POLARSSL_ERR_SHA2_FILE_IO_ERROR -0x0078 /**< Read/write error in file. */
|
||||||
|
|
||||||
|
+#ifdef POLARSSL_SHA2_ALT
|
||||||
|
+
|
||||||
|
+#include "polarssl/sha2_alt.h"
|
||||||
|
+
|
||||||
|
+#else
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* \brief SHA-256 context structure
|
||||||
|
*/
|
||||||
|
@@ -82,6 +90,19 @@
|
||||||
|
*/
|
||||||
|
void sha2_finish( sha2_context *ctx, unsigned char output[32] );
|
||||||
|
|
||||||
|
+/* Internal use */
|
||||||
|
+void sha2_process( sha2_context *ctx, const unsigned char data[64] );
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#endif /* POLARSSL_SHA2_ALT */
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+extern "C" {
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* \brief Output = SHA-256( input buffer )
|
||||||
|
*
|
||||||
|
@@ -160,9 +181,6 @@
|
||||||
|
*/
|
||||||
|
int sha2_self_test( int verbose );
|
||||||
|
|
||||||
|
-/* Internal use */
|
||||||
|
-void sha2_process( sha2_context *ctx, const unsigned char data[64] );
|
||||||
|
-
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
diff -uNr polarssl-1.2.7/include/polarssl/sha2_alt.h polarssl.new/include/polarssl/sha2_alt.h
|
||||||
|
--- polarssl-1.2.7/include/polarssl/sha2_alt.h 1969-12-31 17:00:00.000000000 -0700
|
||||||
|
+++ polarssl.new/include/polarssl/sha2_alt.h 2013-06-07 17:43:56.000000000 -0600
|
||||||
|
@@ -0,0 +1,71 @@
|
||||||
|
+/*
|
||||||
|
+ * Use OpenSSL implementation of SHA2 methods to get asm and hardware acceleration.
|
||||||
|
+ * Don't include this file directly, it is included by sha2.h when
|
||||||
|
+ * POLARSSL_SHA2_ALT is defined.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include "polarssl/sha_openssl.h"
|
||||||
|
+
|
||||||
|
+struct openssl_sha2_context {
|
||||||
|
+ SHA_LONG h[8];
|
||||||
|
+ SHA_LONG Nl,Nh;
|
||||||
|
+ SHA_LONG data[SHA_LBLOCK];
|
||||||
|
+ unsigned int num,md_len;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+typedef struct
|
||||||
|
+{
|
||||||
|
+ struct openssl_sha2_context octx;
|
||||||
|
+
|
||||||
|
+ unsigned char ipad[64]; /*!< HMAC: inner padding */
|
||||||
|
+ unsigned char opad[64]; /*!< HMAC: outer padding */
|
||||||
|
+ int is224; /*!< 0 => SHA-256, else SHA-224 */
|
||||||
|
+}
|
||||||
|
+sha2_context;
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+extern "C" {
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+int SHA224_Init(struct openssl_sha2_context *c);
|
||||||
|
+int SHA224_Update(struct openssl_sha2_context *c, const void *data, size_t len);
|
||||||
|
+int SHA224_Final(unsigned char *md, struct openssl_sha2_context *c);
|
||||||
|
+
|
||||||
|
+int SHA256_Init(struct openssl_sha2_context *c);
|
||||||
|
+int SHA256_Update(struct openssl_sha2_context *c, const void *data, size_t len);
|
||||||
|
+int SHA256_Final(unsigned char *md, struct openssl_sha2_context *c);
|
||||||
|
+
|
||||||
|
+void sha256_block_data_order(struct openssl_sha2_context *c, const void *p, size_t num);
|
||||||
|
+
|
||||||
|
+static inline void sha2_starts( sha2_context *ctx, int is224 )
|
||||||
|
+{
|
||||||
|
+ if ((ctx->is224 = is224))
|
||||||
|
+ SHA224_Init(&ctx->octx);
|
||||||
|
+ else
|
||||||
|
+ SHA256_Init(&ctx->octx);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void sha2_update( sha2_context *ctx, const unsigned char *input, size_t ilen )
|
||||||
|
+{
|
||||||
|
+ if (ctx->is224)
|
||||||
|
+ SHA224_Update(&ctx->octx, input, ilen);
|
||||||
|
+ else
|
||||||
|
+ SHA256_Update(&ctx->octx, input, ilen);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void sha2_finish( sha2_context *ctx, unsigned char output[32] )
|
||||||
|
+{
|
||||||
|
+ if (ctx->is224)
|
||||||
|
+ SHA224_Final(output, &ctx->octx);
|
||||||
|
+ else
|
||||||
|
+ SHA256_Final(output, &ctx->octx);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void sha2_process( sha2_context *ctx, const unsigned char data[64] )
|
||||||
|
+{
|
||||||
|
+ sha256_block_data_order(&ctx->octx, data, 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
diff -uNr polarssl-1.2.7/include/polarssl/sha4.h polarssl.new/include/polarssl/sha4.h
|
||||||
|
--- polarssl-1.2.7/include/polarssl/sha4.h 2013-04-13 03:56:17.000000000 -0600
|
||||||
|
+++ polarssl.new/include/polarssl/sha4.h 2013-06-07 17:43:56.000000000 -0600
|
||||||
|
@@ -29,6 +29,8 @@
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
+#include "config.h"
|
||||||
|
+
|
||||||
|
#if defined(_MSC_VER) || defined(__WATCOMC__)
|
||||||
|
#define UL64(x) x##ui64
|
||||||
|
typedef unsigned __int64 uint64_t;
|
||||||
|
@@ -39,6 +41,12 @@
|
||||||
|
|
||||||
|
#define POLARSSL_ERR_SHA4_FILE_IO_ERROR -0x007A /**< Read/write error in file. */
|
||||||
|
|
||||||
|
+#ifdef POLARSSL_SHA4_ALT
|
||||||
|
+
|
||||||
|
+#include "polarssl/sha4_alt.h"
|
||||||
|
+
|
||||||
|
+#else
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* \brief SHA-512 context structure
|
||||||
|
*/
|
||||||
|
@@ -83,6 +91,16 @@
|
||||||
|
*/
|
||||||
|
void sha4_finish( sha4_context *ctx, unsigned char output[64] );
|
||||||
|
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#endif /* POLARSSL_SHA4_ALT */
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+extern "C" {
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
/**
|
||||||
|
* \brief Output = SHA-512( input buffer )
|
||||||
|
*
|
||||||
|
diff -uNr polarssl-1.2.7/include/polarssl/sha4_alt.h polarssl.new/include/polarssl/sha4_alt.h
|
||||||
|
--- polarssl-1.2.7/include/polarssl/sha4_alt.h 1969-12-31 17:00:00.000000000 -0700
|
||||||
|
+++ polarssl.new/include/polarssl/sha4_alt.h 2013-06-07 17:43:56.000000000 -0600
|
||||||
|
@@ -0,0 +1,67 @@
|
||||||
|
+/*
|
||||||
|
+ * Use OpenSSL implementation of SHA4 methods to get asm and hardware acceleration.
|
||||||
|
+ * Don't include this file directly, it is included by sha4.h when
|
||||||
|
+ * POLARSSL_SHA4_ALT is defined.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include "polarssl/sha_openssl.h"
|
||||||
|
+
|
||||||
|
+struct openssl_sha4_context {
|
||||||
|
+ SHA_LONG64 h[8];
|
||||||
|
+ SHA_LONG64 Nl,Nh;
|
||||||
|
+ union {
|
||||||
|
+ SHA_LONG64 d[SHA_LBLOCK];
|
||||||
|
+ unsigned char p[SHA512_CBLOCK];
|
||||||
|
+ } u;
|
||||||
|
+ unsigned int num,md_len;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+typedef struct
|
||||||
|
+{
|
||||||
|
+ struct openssl_sha4_context octx;
|
||||||
|
+
|
||||||
|
+ unsigned char ipad[128]; /*!< HMAC: inner padding */
|
||||||
|
+ unsigned char opad[128]; /*!< HMAC: outer padding */
|
||||||
|
+ int is384; /*!< 0 => SHA-512, else SHA-384 */
|
||||||
|
+}
|
||||||
|
+sha4_context;
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+extern "C" {
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+int SHA384_Init(struct openssl_sha4_context *c);
|
||||||
|
+int SHA384_Update(struct openssl_sha4_context *c, const void *data, size_t len);
|
||||||
|
+int SHA384_Final(unsigned char *md, struct openssl_sha4_context *c);
|
||||||
|
+
|
||||||
|
+int SHA512_Init(struct openssl_sha4_context *c);
|
||||||
|
+int SHA512_Update(struct openssl_sha4_context *c, const void *data, size_t len);
|
||||||
|
+int SHA512_Final(unsigned char *md, struct openssl_sha4_context *c);
|
||||||
|
+
|
||||||
|
+static inline void sha4_starts( sha4_context *ctx, int is384 )
|
||||||
|
+{
|
||||||
|
+ if ((ctx->is384 = is384))
|
||||||
|
+ SHA384_Init(&ctx->octx);
|
||||||
|
+ else
|
||||||
|
+ SHA512_Init(&ctx->octx);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void sha4_update( sha4_context *ctx, const unsigned char *input, size_t ilen )
|
||||||
|
+{
|
||||||
|
+ if (ctx->is384)
|
||||||
|
+ SHA384_Update(&ctx->octx, input, ilen);
|
||||||
|
+ else
|
||||||
|
+ SHA512_Update(&ctx->octx, input, ilen);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void sha4_finish( sha4_context *ctx, unsigned char output[64] )
|
||||||
|
+{
|
||||||
|
+ if (ctx->is384)
|
||||||
|
+ SHA384_Final(output, &ctx->octx);
|
||||||
|
+ else
|
||||||
|
+ SHA512_Final(output, &ctx->octx);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
diff -uNr polarssl-1.2.7/include/polarssl/sha_openssl.h polarssl.new/include/polarssl/sha_openssl.h
|
||||||
|
--- polarssl-1.2.7/include/polarssl/sha_openssl.h 1969-12-31 17:00:00.000000000 -0700
|
||||||
|
+++ polarssl.new/include/polarssl/sha_openssl.h 2013-06-07 17:43:56.000000000 -0600
|
||||||
|
@@ -0,0 +1,42 @@
|
||||||
|
+/*
|
||||||
|
+ * Common header file for all OpenSSL-imported SHA methods
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#ifndef POLARSSL_SHA_OPENSSL_H
|
||||||
|
+#define POLARSSL_SHA_OPENSSL_H
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
+ * ! SHA_LONG has to be at least 32 bits wide. If it's wider, then !
|
||||||
|
+ * ! SHA_LONG_LOG2 has to be defined along. !
|
||||||
|
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#if defined(__LP32__)
|
||||||
|
+#define SHA_LONG unsigned long
|
||||||
|
+#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__)
|
||||||
|
+#define SHA_LONG unsigned long
|
||||||
|
+#define SHA_LONG_LOG2 3
|
||||||
|
+#else
|
||||||
|
+#define SHA_LONG unsigned int
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#define SHA_LBLOCK 16
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Unlike 32-bit digest algorithms, SHA-512 *relies* on SHA_LONG64
|
||||||
|
+ * being exactly 64-bit wide. See Implementation Notes in sha512.c
|
||||||
|
+ * for further details.
|
||||||
|
+ */
|
||||||
|
+#define SHA512_CBLOCK (SHA_LBLOCK*8) /* SHA-512 treats input data as a
|
||||||
|
+ * contiguous array of 64 bit
|
||||||
|
+ * wide big-endian values. */
|
||||||
|
+#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__)
|
||||||
|
+#define SHA_LONG64 unsigned __int64
|
||||||
|
+#elif defined(__arch64__)
|
||||||
|
+#define SHA_LONG64 unsigned long
|
||||||
|
+#else
|
||||||
|
+#define SHA_LONG64 unsigned long long
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#endif
|
||||||
|
diff -uNr polarssl-1.2.7/library/aes.c polarssl.new/library/aes.c
|
||||||
|
--- polarssl-1.2.7/library/aes.c 2013-04-13 03:56:17.000000000 -0600
|
||||||
|
+++ polarssl.new/library/aes.c 2013-06-07 17:43:56.000000000 -0600
|
||||||
|
@@ -38,6 +38,8 @@
|
||||||
|
#include "polarssl/padlock.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+#ifndef POLARSSL_AES_ALT
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* 32-bit integer manipulation macros (little endian)
|
||||||
|
*/
|
||||||
|
@@ -914,6 +916,7 @@
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
#endif /* POLARSSL_CIPHER_MODE_CTR */
|
||||||
|
+#endif /* !POLARSSL_AES_ALT */
|
||||||
|
|
||||||
|
#if defined(POLARSSL_SELF_TEST)
|
||||||
|
|
||||||
|
diff -uNr polarssl-1.2.7/library/sha1.c polarssl.new/library/sha1.c
|
||||||
|
--- polarssl-1.2.7/library/sha1.c 2013-04-13 03:56:17.000000000 -0600
|
||||||
|
+++ polarssl.new/library/sha1.c 2013-06-07 17:43:56.000000000 -0600
|
||||||
|
@@ -38,6 +38,8 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+#ifndef POLARSSL_SHA1_ALT
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* 32-bit integer manipulation macros (big endian)
|
||||||
|
*/
|
||||||
|
@@ -313,6 +315,8 @@
|
||||||
|
PUT_UINT32_BE( ctx->state[4], output, 16 );
|
||||||
|
}
|
||||||
|
|
||||||
|
+#endif /* !POLARSSL_SHA1_ALT */
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* output = SHA-1( input buffer )
|
||||||
|
*/
|
||||||
|
diff -uNr polarssl-1.2.7/library/sha2.c polarssl.new/library/sha2.c
|
||||||
|
--- polarssl-1.2.7/library/sha2.c 2013-04-13 03:56:17.000000000 -0600
|
||||||
|
+++ polarssl.new/library/sha2.c 2013-06-07 17:43:56.000000000 -0600
|
||||||
|
@@ -38,6 +38,8 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+#ifndef POLARSSL_SHA2_ALT
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* 32-bit integer manipulation macros (big endian)
|
||||||
|
*/
|
||||||
|
@@ -314,6 +316,8 @@
|
||||||
|
PUT_UINT32_BE( ctx->state[7], output, 28 );
|
||||||
|
}
|
||||||
|
|
||||||
|
+#endif /* !POLARSSL_SHA2_ALT */
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* output = SHA-256( input buffer )
|
||||||
|
*/
|
||||||
|
diff -uNr polarssl-1.2.7/library/sha4.c polarssl.new/library/sha4.c
|
||||||
|
--- polarssl-1.2.7/library/sha4.c 2013-04-13 03:56:17.000000000 -0600
|
||||||
|
+++ polarssl.new/library/sha4.c 2013-06-07 17:43:56.000000000 -0600
|
||||||
|
@@ -38,6 +38,8 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+#ifndef POLARSSL_SHA4_ALT
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* 64-bit integer manipulation macros (big endian)
|
||||||
|
*/
|
||||||
|
@@ -312,6 +314,8 @@
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+#endif /* !POLARSSL_SHA4_ALT */
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* output = SHA-512( input buffer )
|
||||||
|
*/
|
||||||
|
diff -uNr polarssl-1.2.7/library/ssl_tls.c polarssl.new/library/ssl_tls.c
|
||||||
|
--- polarssl-1.2.7/library/ssl_tls.c 2013-04-13 03:56:17.000000000 -0600
|
||||||
|
+++ polarssl.new/library/ssl_tls.c 2013-06-07 17:43:56.000000000 -0600
|
||||||
|
@@ -2550,8 +2550,10 @@
|
||||||
|
SSL_DEBUG_BUF( 4, "finished md5 state", (unsigned char *)
|
||||||
|
md5.state, sizeof( md5.state ) );
|
||||||
|
|
||||||
|
+#ifndef POLARSSL_SHA1_ALT
|
||||||
|
SSL_DEBUG_BUF( 4, "finished sha1 state", (unsigned char *)
|
||||||
|
sha1.state, sizeof( sha1.state ) );
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
sender = ( from == SSL_IS_CLIENT ) ? (char *) "CLNT"
|
||||||
|
: (char *) "SRVR";
|
||||||
|
@@ -2621,8 +2623,10 @@
|
||||||
|
SSL_DEBUG_BUF( 4, "finished md5 state", (unsigned char *)
|
||||||
|
md5.state, sizeof( md5.state ) );
|
||||||
|
|
||||||
|
+#ifndef POLARSSL_SHA1_ALT
|
||||||
|
SSL_DEBUG_BUF( 4, "finished sha1 state", (unsigned char *)
|
||||||
|
sha1.state, sizeof( sha1.state ) );
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
sender = ( from == SSL_IS_CLIENT )
|
||||||
|
? (char *) "client finished"
|
||||||
|
@@ -2666,8 +2670,10 @@
|
||||||
|
* Hash( handshake ) )[0.11]
|
||||||
|
*/
|
||||||
|
|
||||||
|
+#ifndef POLARSSL_SHA2_ALT
|
||||||
|
SSL_DEBUG_BUF( 4, "finished sha2 state", (unsigned char *)
|
||||||
|
sha2.state, sizeof( sha2.state ) );
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
sender = ( from == SSL_IS_CLIENT )
|
||||||
|
? (char *) "client finished"
|
||||||
|
@@ -2710,8 +2716,10 @@
|
||||||
|
* Hash( handshake ) )[0.11]
|
||||||
|
*/
|
||||||
|
|
||||||
|
+#ifndef POLARSSL_SHA4_ALT
|
||||||
|
SSL_DEBUG_BUF( 4, "finished sha4 state", (unsigned char *)
|
||||||
|
sha4.state, sizeof( sha4.state ) );
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
sender = ( from == SSL_IS_CLIENT )
|
||||||
|
? (char *) "client finished"
|
||||||
|
diff -uNr polarssl-1.2.7/tests/suites/test_suite_aes.function polarssl.new/tests/suites/test_suite_aes.function
|
||||||
|
--- polarssl-1.2.7/tests/suites/test_suite_aes.function 2013-04-13 03:56:17.000000000 -0600
|
||||||
|
+++ polarssl.new/tests/suites/test_suite_aes.function 2013-06-07 17:43:56.000000000 -0600
|
||||||
|
@@ -1,4 +1,5 @@
|
||||||
|
BEGIN_HEADER
|
||||||
|
+#include <polarssl/config.h>
|
||||||
|
#include <polarssl/aes.h>
|
||||||
|
END_HEADER
|
||||||
|
|
||||||
|
diff -uNr polarssl-1.2.7/tests/suites/test_suite_ctr_drbg.function polarssl.new/tests/suites/test_suite_ctr_drbg.function
|
||||||
|
--- polarssl-1.2.7/tests/suites/test_suite_ctr_drbg.function 2013-04-13 03:56:17.000000000 -0600
|
||||||
|
+++ polarssl.new/tests/suites/test_suite_ctr_drbg.function 2013-06-07 17:43:56.000000000 -0600
|
||||||
|
@@ -1,4 +1,5 @@
|
||||||
|
BEGIN_HEADER
|
||||||
|
+#include <polarssl/config.h>
|
||||||
|
#include <polarssl/ctr_drbg.h>
|
||||||
|
|
||||||
|
int test_offset;
|
||||||
@@ -0,0 +1,446 @@
|
|||||||
|
diff -uNr polarssl-1.2.7/include/polarssl/aes_alt.h polarssl.new/include/polarssl/aes_alt.h
|
||||||
|
--- polarssl-1.2.7/include/polarssl/aes_alt.h 1969-12-31 17:00:00.000000000 -0700
|
||||||
|
+++ polarssl.new/include/polarssl/aes_alt.h 2013-06-07 18:18:37.000000000 -0600
|
||||||
|
@@ -0,0 +1,183 @@
|
||||||
|
+/*
|
||||||
|
+ * Use OpenSSL implementation of AES methods to get asm and hardware acceleration.
|
||||||
|
+ * Don't include this file directly, it is included by aes.h when
|
||||||
|
+ * POLARSSL_AES_ALT is defined.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#ifdef _MSC_VER
|
||||||
|
+#include <basetsd.h>
|
||||||
|
+typedef UINT32 uint32_t;
|
||||||
|
+#else
|
||||||
|
+#include <inttypes.h>
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#define OPENSSL_AES_BLOCK_SIZE 16
|
||||||
|
+#define OPENSSL_AES_MAXNR 14
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * \brief AES context structure
|
||||||
|
+ */
|
||||||
|
+typedef struct
|
||||||
|
+{
|
||||||
|
+ uint32_t rd_key[4 * (OPENSSL_AES_MAXNR + 1)];
|
||||||
|
+ int rounds;
|
||||||
|
+}
|
||||||
|
+aes_context;
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+extern "C" {
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#if defined(POLARSSL_USE_OPENSSL_AES_NI)
|
||||||
|
+
|
||||||
|
+int aesni_set_encrypt_key(const unsigned char *userKey, const int bits,
|
||||||
|
+ aes_context *key);
|
||||||
|
+int aesni_set_decrypt_key(const unsigned char *userKey, const int bits,
|
||||||
|
+ aes_context *key);
|
||||||
|
+void aesni_ecb_encrypt(const unsigned char *in, unsigned char *out,
|
||||||
|
+ size_t length, const aes_context *key, const int enc);
|
||||||
|
+void aesni_cbc_encrypt(const unsigned char *in, unsigned char *out,
|
||||||
|
+ size_t length, const aes_context *key,
|
||||||
|
+ unsigned char *ivec, const int enc);
|
||||||
|
+
|
||||||
|
+#define OPENSSL_AES_SET_ENCRYPT_KEY(k,b,c) aesni_set_encrypt_key(k,b,c)
|
||||||
|
+#define OPENSSL_AES_SET_DECRYPT_KEY(k,b,c) aesni_set_decrypt_key(k,b,c)
|
||||||
|
+#define OPENSSL_AES_ECB_ENCRYPT(i,o,k) aesni_ecb_encrypt(i,o,16,k,AES_ENCRYPT)
|
||||||
|
+#define OPENSSL_AES_ECB_DECRYPT(i,o,k) aesni_ecb_encrypt(i,o,16,k,AES_DECRYPT)
|
||||||
|
+#define OPENSSL_AES_CBC_ENCRYPT(i,o,l,k,iv,e) aesni_cbc_encrypt(i,o,l,k,iv,e)
|
||||||
|
+
|
||||||
|
+#else
|
||||||
|
+
|
||||||
|
+int AES_set_encrypt_key(const unsigned char *userKey, const int bits,
|
||||||
|
+ aes_context *key);
|
||||||
|
+int AES_set_decrypt_key(const unsigned char *userKey, const int bits,
|
||||||
|
+ aes_context *key);
|
||||||
|
+
|
||||||
|
+void AES_encrypt(const unsigned char *in, unsigned char *out, const aes_context *key);
|
||||||
|
+void AES_decrypt(const unsigned char *in, unsigned char *out, const aes_context *key);
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+#define OPENSSL_AES_SET_ENCRYPT_KEY(k,b,c) AES_set_encrypt_key(k,b,c)
|
||||||
|
+#define OPENSSL_AES_SET_DECRYPT_KEY(k,b,c) AES_set_decrypt_key(k,b,c)
|
||||||
|
+#define OPENSSL_AES_ECB_ENCRYPT(i,o,k) AES_encrypt(i,o,k)
|
||||||
|
+#define OPENSSL_AES_ECB_DECRYPT(i,o,k) AES_decrypt(i,o,k)
|
||||||
|
+
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * \brief AES key schedule (encryption)
|
||||||
|
+ *
|
||||||
|
+ * \param ctx AES context to be initialized
|
||||||
|
+ * \param key encryption key
|
||||||
|
+ * \param keysize must be 128, 192 or 256
|
||||||
|
+ *
|
||||||
|
+ * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH
|
||||||
|
+ */
|
||||||
|
+static inline int aes_setkey_enc( aes_context *ctx, const unsigned char *key, const unsigned int keysize )
|
||||||
|
+{
|
||||||
|
+ const int status = OPENSSL_AES_SET_ENCRYPT_KEY(key, keysize, ctx);
|
||||||
|
+ return status ? POLARSSL_ERR_AES_INVALID_KEY_LENGTH : 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * \brief AES key schedule (decryption)
|
||||||
|
+ *
|
||||||
|
+ * \param ctx AES context to be initialized
|
||||||
|
+ * \param key decryption key
|
||||||
|
+ * \param keysize must be 128, 192 or 256
|
||||||
|
+ *
|
||||||
|
+ * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_KEY_LENGTH
|
||||||
|
+ */
|
||||||
|
+static inline int aes_setkey_dec( aes_context *ctx, const unsigned char *key, const unsigned int keysize )
|
||||||
|
+{
|
||||||
|
+ const int status = OPENSSL_AES_SET_DECRYPT_KEY(key, keysize, ctx);
|
||||||
|
+ return status ? POLARSSL_ERR_AES_INVALID_KEY_LENGTH : 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * \brief AES-ECB block encryption/decryption
|
||||||
|
+ *
|
||||||
|
+ * \param ctx AES context
|
||||||
|
+ * \param mode AES_ENCRYPT or AES_DECRYPT
|
||||||
|
+ * \param input 16-byte input block
|
||||||
|
+ * \param output 16-byte output block
|
||||||
|
+ *
|
||||||
|
+ * \return 0 if successful
|
||||||
|
+ */
|
||||||
|
+static inline int aes_crypt_ecb( aes_context *ctx,
|
||||||
|
+ const int mode,
|
||||||
|
+ const unsigned char input[16],
|
||||||
|
+ unsigned char output[16] )
|
||||||
|
+{
|
||||||
|
+ if (mode == AES_DECRYPT)
|
||||||
|
+ OPENSSL_AES_ECB_DECRYPT(input, output, ctx);
|
||||||
|
+ else
|
||||||
|
+ OPENSSL_AES_ECB_ENCRYPT(input, output, ctx);
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * \brief AES-CBC buffer encryption/decryption
|
||||||
|
+ * Length should be a multiple of the block
|
||||||
|
+ * size (16 bytes)
|
||||||
|
+ *
|
||||||
|
+ * \param ctx AES context
|
||||||
|
+ * \param mode AES_ENCRYPT or AES_DECRYPT
|
||||||
|
+ * \param length length of the input data
|
||||||
|
+ * \param iv initialization vector (updated after use)
|
||||||
|
+ * \param input buffer holding the input data
|
||||||
|
+ * \param output buffer holding the output data
|
||||||
|
+ *
|
||||||
|
+ * \return 0 if successful, or POLARSSL_ERR_AES_INVALID_INPUT_LENGTH
|
||||||
|
+ */
|
||||||
|
+static inline int aes_crypt_cbc( aes_context *ctx,
|
||||||
|
+ const int mode,
|
||||||
|
+ size_t length,
|
||||||
|
+ unsigned char iv[16],
|
||||||
|
+ const unsigned char *input,
|
||||||
|
+ unsigned char *output )
|
||||||
|
+{
|
||||||
|
+#ifdef OPENSSL_AES_CBC_ENCRYPT
|
||||||
|
+ if (length & (OPENSSL_AES_BLOCK_SIZE-1))
|
||||||
|
+ return POLARSSL_ERR_AES_INVALID_INPUT_LENGTH;
|
||||||
|
+ OPENSSL_AES_CBC_ENCRYPT(input, output, length, ctx, iv, mode);
|
||||||
|
+ return 0;
|
||||||
|
+#else
|
||||||
|
+ int i;
|
||||||
|
+ unsigned char temp[16];
|
||||||
|
+ if (length & (OPENSSL_AES_BLOCK_SIZE-1))
|
||||||
|
+ return POLARSSL_ERR_AES_INVALID_INPUT_LENGTH;
|
||||||
|
+ if( mode == AES_DECRYPT )
|
||||||
|
+ {
|
||||||
|
+ while( length > 0 )
|
||||||
|
+ {
|
||||||
|
+ memcpy( temp, input, 16 );
|
||||||
|
+ OPENSSL_AES_ECB_DECRYPT(input, output, ctx);
|
||||||
|
+ for( i = 0; i < 16; i++ )
|
||||||
|
+ output[i] = (unsigned char)( output[i] ^ iv[i] );
|
||||||
|
+ memcpy( iv, temp, 16 );
|
||||||
|
+ input += 16;
|
||||||
|
+ output += 16;
|
||||||
|
+ length -= 16;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+ while( length > 0 )
|
||||||
|
+ {
|
||||||
|
+ for( i = 0; i < 16; i++ )
|
||||||
|
+ output[i] = (unsigned char)( input[i] ^ iv[i] );
|
||||||
|
+ OPENSSL_AES_ECB_ENCRYPT(output, output, ctx);
|
||||||
|
+ memcpy( iv, output, 16 );
|
||||||
|
+ input += 16;
|
||||||
|
+ output += 16;
|
||||||
|
+ length -= 16;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ return( 0 );
|
||||||
|
+#endif
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
diff -uNr polarssl-1.2.7/include/polarssl/sha1_alt.h polarssl.new/include/polarssl/sha1_alt.h
|
||||||
|
--- polarssl-1.2.7/include/polarssl/sha1_alt.h 1969-12-31 17:00:00.000000000 -0700
|
||||||
|
+++ polarssl.new/include/polarssl/sha1_alt.h 2013-06-07 17:43:56.000000000 -0600
|
||||||
|
@@ -0,0 +1,56 @@
|
||||||
|
+/*
|
||||||
|
+ * Use OpenSSL implementation of SHA1 methods to get asm and hardware acceleration.
|
||||||
|
+ * Don't include this file directly, it is included by sha1.h when
|
||||||
|
+ * POLARSSL_SHA1_ALT is defined.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include "polarssl/sha_openssl.h"
|
||||||
|
+
|
||||||
|
+struct openssl_sha_context {
|
||||||
|
+ SHA_LONG h0,h1,h2,h3,h4;
|
||||||
|
+ SHA_LONG Nl,Nh;
|
||||||
|
+ SHA_LONG data[SHA_LBLOCK];
|
||||||
|
+ unsigned int num;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+typedef struct
|
||||||
|
+{
|
||||||
|
+ struct openssl_sha_context octx;
|
||||||
|
+
|
||||||
|
+ unsigned char ipad[64]; /*!< HMAC: inner padding */
|
||||||
|
+ unsigned char opad[64]; /*!< HMAC: outer padding */
|
||||||
|
+}
|
||||||
|
+sha1_context;
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+extern "C" {
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+int SHA1_Init(struct openssl_sha_context *c);
|
||||||
|
+int SHA1_Update(struct openssl_sha_context *c, const void *data, size_t len);
|
||||||
|
+int SHA1_Final(unsigned char *md, struct openssl_sha_context *c);
|
||||||
|
+void sha1_block_data_order(struct openssl_sha_context *c, const void *p, size_t num);
|
||||||
|
+
|
||||||
|
+static inline void sha1_starts( sha1_context *ctx )
|
||||||
|
+{
|
||||||
|
+ SHA1_Init(&ctx->octx);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void sha1_update( sha1_context *ctx, const unsigned char *input, size_t ilen )
|
||||||
|
+{
|
||||||
|
+ SHA1_Update(&ctx->octx, input, ilen);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void sha1_finish( sha1_context *ctx, unsigned char output[20] )
|
||||||
|
+{
|
||||||
|
+ SHA1_Final(output, &ctx->octx);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void sha1_process( sha1_context *ctx, const unsigned char data[64] )
|
||||||
|
+{
|
||||||
|
+ sha1_block_data_order(&ctx->octx, data, 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
diff -uNr polarssl-1.2.7/include/polarssl/sha256_alt.h polarssl.new/include/polarssl/sha256_alt.h
|
||||||
|
--- polarssl-1.2.7/include/polarssl/sha256_alt.h 1969-12-31 17:00:00.000000000 -0700
|
||||||
|
+++ polarssl.new/include/polarssl/sha256_alt.h 2013-06-07 17:43:56.000000000 -0600
|
||||||
|
@@ -0,0 +1,71 @@
|
||||||
|
+/*
|
||||||
|
+ * Use OpenSSL implementation of SHA256 methods to get asm and hardware acceleration.
|
||||||
|
+ * Don't include this file directly, it is included by sha256.h when
|
||||||
|
+ * POLARSSL_SHA256_ALT is defined.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include "polarssl/sha_openssl.h"
|
||||||
|
+
|
||||||
|
+struct openssl_sha256_context {
|
||||||
|
+ SHA_LONG h[8];
|
||||||
|
+ SHA_LONG Nl,Nh;
|
||||||
|
+ SHA_LONG data[SHA_LBLOCK];
|
||||||
|
+ unsigned int num,md_len;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+typedef struct
|
||||||
|
+{
|
||||||
|
+ struct openssl_sha256_context octx;
|
||||||
|
+
|
||||||
|
+ unsigned char ipad[64]; /*!< HMAC: inner padding */
|
||||||
|
+ unsigned char opad[64]; /*!< HMAC: outer padding */
|
||||||
|
+ int is224; /*!< 0 => SHA-256, else SHA-224 */
|
||||||
|
+}
|
||||||
|
+sha256_context;
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+extern "C" {
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+int SHA224_Init(struct openssl_sha256_context *c);
|
||||||
|
+int SHA224_Update(struct openssl_sha256_context *c, const void *data, size_t len);
|
||||||
|
+int SHA224_Final(unsigned char *md, struct openssl_sha256_context *c);
|
||||||
|
+
|
||||||
|
+int SHA256_Init(struct openssl_sha256_context *c);
|
||||||
|
+int SHA256_Update(struct openssl_sha256_context *c, const void *data, size_t len);
|
||||||
|
+int SHA256_Final(unsigned char *md, struct openssl_sha256_context *c);
|
||||||
|
+
|
||||||
|
+void sha256_block_data_order(struct openssl_sha256_context *c, const void *p, size_t num);
|
||||||
|
+
|
||||||
|
+static inline void sha256_starts( sha256_context *ctx, int is224 )
|
||||||
|
+{
|
||||||
|
+ if ((ctx->is224 = is224))
|
||||||
|
+ SHA224_Init(&ctx->octx);
|
||||||
|
+ else
|
||||||
|
+ SHA256_Init(&ctx->octx);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void sha256_update( sha256_context *ctx, const unsigned char *input, size_t ilen )
|
||||||
|
+{
|
||||||
|
+ if (ctx->is224)
|
||||||
|
+ SHA224_Update(&ctx->octx, input, ilen);
|
||||||
|
+ else
|
||||||
|
+ SHA256_Update(&ctx->octx, input, ilen);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void sha256_finish( sha256_context *ctx, unsigned char output[32] )
|
||||||
|
+{
|
||||||
|
+ if (ctx->is224)
|
||||||
|
+ SHA224_Final(output, &ctx->octx);
|
||||||
|
+ else
|
||||||
|
+ SHA256_Final(output, &ctx->octx);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void sha256_process( sha256_context *ctx, const unsigned char data[64] )
|
||||||
|
+{
|
||||||
|
+ sha256_block_data_order(&ctx->octx, data, 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
diff -uNr polarssl-1.2.7/include/polarssl/sha512_alt.h polarssl.new/include/polarssl/sha512_alt.h
|
||||||
|
--- polarssl-1.2.7/include/polarssl/sha512_alt.h 1969-12-31 17:00:00.000000000 -0700
|
||||||
|
+++ polarssl.new/include/polarssl/sha512_alt.h 2013-06-07 17:43:56.000000000 -0600
|
||||||
|
@@ -0,0 +1,74 @@
|
||||||
|
+/*
|
||||||
|
+ * Use OpenSSL implementation of SHA512 methods to get asm and hardware acceleration.
|
||||||
|
+ * Don't include this file directly, it is included by sha512.h when
|
||||||
|
+ * POLARSSL_SHA512_ALT is defined.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include "polarssl/sha_openssl.h"
|
||||||
|
+
|
||||||
|
+struct openssl_sha512_context {
|
||||||
|
+ SHA_LONG64 h[8];
|
||||||
|
+ SHA_LONG64 Nl,Nh;
|
||||||
|
+ union {
|
||||||
|
+ SHA_LONG64 d[SHA_LBLOCK];
|
||||||
|
+ unsigned char p[SHA512_CBLOCK];
|
||||||
|
+ } u;
|
||||||
|
+ unsigned int num,md_len;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+typedef struct
|
||||||
|
+{
|
||||||
|
+ struct openssl_sha512_context octx;
|
||||||
|
+
|
||||||
|
+ unsigned char ipad[128]; /*!< HMAC: inner padding */
|
||||||
|
+ unsigned char opad[128]; /*!< HMAC: outer padding */
|
||||||
|
+ int is384; /*!< 0 => SHA-512, else SHA-384 */
|
||||||
|
+}
|
||||||
|
+sha512_context;
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+extern "C" {
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+int SHA384_Init(struct openssl_sha512_context *c);
|
||||||
|
+int SHA384_Update(struct openssl_sha512_context *c, const void *data, size_t len);
|
||||||
|
+int SHA384_Final(unsigned char *md, struct openssl_sha512_context *c);
|
||||||
|
+
|
||||||
|
+int SHA512_Init(struct openssl_sha512_context *c);
|
||||||
|
+int SHA512_Update(struct openssl_sha512_context *c, const void *data, size_t len);
|
||||||
|
+int SHA512_Final(unsigned char *md, struct openssl_sha512_context *c);
|
||||||
|
+
|
||||||
|
+void sha512_block_data_order(struct openssl_sha512_context *c, const void *p, size_t num);
|
||||||
|
+
|
||||||
|
+static inline void sha512_starts( sha512_context *ctx, int is384 )
|
||||||
|
+{
|
||||||
|
+ if ((ctx->is384 = is384))
|
||||||
|
+ SHA384_Init(&ctx->octx);
|
||||||
|
+ else
|
||||||
|
+ SHA512_Init(&ctx->octx);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void sha512_update( sha512_context *ctx, const unsigned char *input, size_t ilen )
|
||||||
|
+{
|
||||||
|
+ if (ctx->is384)
|
||||||
|
+ SHA384_Update(&ctx->octx, input, ilen);
|
||||||
|
+ else
|
||||||
|
+ SHA512_Update(&ctx->octx, input, ilen);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void sha512_finish( sha512_context *ctx, unsigned char output[64] )
|
||||||
|
+{
|
||||||
|
+ if (ctx->is384)
|
||||||
|
+ SHA384_Final(output, &ctx->octx);
|
||||||
|
+ else
|
||||||
|
+ SHA512_Final(output, &ctx->octx);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline void sha512_process( sha512_context *ctx, const unsigned char data[128] )
|
||||||
|
+{
|
||||||
|
+ sha512_block_data_order(&ctx->octx, data, 1);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#ifdef __cplusplus
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
diff -uNr polarssl-1.2.7/include/polarssl/sha_openssl.h polarssl.new/include/polarssl/sha_openssl.h
|
||||||
|
--- polarssl-1.2.7/include/polarssl/sha_openssl.h 1969-12-31 17:00:00.000000000 -0700
|
||||||
|
+++ polarssl.new/include/polarssl/sha_openssl.h 2013-06-07 17:43:56.000000000 -0600
|
||||||
|
@@ -0,0 +1,42 @@
|
||||||
|
+/*
|
||||||
|
+ * Common header file for all OpenSSL-imported SHA methods
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#ifndef POLARSSL_SHA_OPENSSL_H
|
||||||
|
+#define POLARSSL_SHA_OPENSSL_H
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
+ * ! SHA_LONG has to be at least 32 bits wide. If it's wider, then !
|
||||||
|
+ * ! SHA_LONG_LOG2 has to be defined along. !
|
||||||
|
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#if defined(__LP32__)
|
||||||
|
+#define SHA_LONG unsigned long
|
||||||
|
+#elif defined(OPENSSL_SYS_CRAY) || defined(__ILP64__)
|
||||||
|
+#define SHA_LONG unsigned long
|
||||||
|
+#define SHA_LONG_LOG2 3
|
||||||
|
+#else
|
||||||
|
+#define SHA_LONG unsigned int
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#define SHA_LBLOCK 16
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Unlike 32-bit digest algorithms, SHA-512 *relies* on SHA_LONG64
|
||||||
|
+ * being exactly 64-bit wide. See Implementation Notes in sha512.c
|
||||||
|
+ * for further details.
|
||||||
|
+ */
|
||||||
|
+#define SHA512_CBLOCK (SHA_LBLOCK*8) /* SHA-512 treats input data as a
|
||||||
|
+ * contiguous array of 64 bit
|
||||||
|
+ * wide big-endian values. */
|
||||||
|
+#if (defined(_WIN32) || defined(_WIN64)) && !defined(__MINGW32__)
|
||||||
|
+#define SHA_LONG64 unsigned __int64
|
||||||
|
+#elif defined(__arch64__)
|
||||||
|
+#define SHA_LONG64 unsigned long
|
||||||
|
+#else
|
||||||
|
+#define SHA_LONG64 unsigned long long
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+#endif
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
AES_set_encrypt_key
|
||||||
|
AES_set_decrypt_key
|
||||||
|
AES_ecb_encrypt
|
||||||
|
AES_cbc_encrypt
|
||||||
|
BF_set_key
|
||||||
|
BF_ecb_encrypt
|
||||||
|
BF_cbc_encrypt
|
||||||
|
SHA1_Init
|
||||||
|
SHA1_Update
|
||||||
|
SHA1_Final
|
||||||
|
SHA224_Init
|
||||||
|
SHA224_Update
|
||||||
|
SHA224_Final
|
||||||
|
SHA256_Init
|
||||||
|
SHA256_Update
|
||||||
|
SHA256_Final
|
||||||
|
SHA384_Init
|
||||||
|
SHA384_Update
|
||||||
|
SHA384_Final
|
||||||
|
SHA512_Init
|
||||||
|
SHA512_Update
|
||||||
|
SHA512_Final
|
||||||
|
OPENSSL_ia32_cpuid
|
||||||
|
-OPENSSL_cpuid_setup
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
aesni_set_encrypt_key
|
||||||
|
aesni_set_decrypt_key
|
||||||
|
aesni_ecb_encrypt
|
||||||
|
aesni_cbc_encrypt
|
||||||
|
BF_set_key
|
||||||
|
BF_ecb_encrypt
|
||||||
|
BF_cbc_encrypt
|
||||||
|
SHA1_Init
|
||||||
|
SHA1_Update
|
||||||
|
SHA1_Final
|
||||||
|
SHA224_Init
|
||||||
|
SHA224_Update
|
||||||
|
SHA224_Final
|
||||||
|
SHA256_Init
|
||||||
|
SHA256_Update
|
||||||
|
SHA256_Final
|
||||||
|
SHA384_Init
|
||||||
|
SHA384_Update
|
||||||
|
SHA384_Final
|
||||||
|
SHA512_Init
|
||||||
|
SHA512_Update
|
||||||
|
SHA512_Final
|
||||||
|
OPENSSL_ia32_cpuid
|
||||||
|
-OPENSSL_cpuid_setup
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
diff -ur mbedtls-1.3.17/library/x509.c polarssl.new/library/x509.c
|
||||||
|
--- mbedtls-1.3.17/library/x509.c 2016-06-27 13:00:26.000000000 -0600
|
||||||
|
+++ polarssl.new/library/x509.c 2016-08-04 17:21:52.000000000 -0600
|
||||||
|
@@ -490,6 +490,73 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
+ * Parse an ASN1_UTC_TIME (yearlen=2) or ASN1_GENERALIZED_TIME (yearlen=4) field.
|
||||||
|
+ */
|
||||||
|
+static int x509_parse_time(unsigned char **p, size_t len, unsigned int yearlen, x509_time *time)
|
||||||
|
+{
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ /* minimum length is 10 or 12 depending on yearlen */
|
||||||
|
+ if (len < yearlen + 8)
|
||||||
|
+ return POLARSSL_ERR_X509_INVALID_DATE;
|
||||||
|
+ len -= yearlen + 8;
|
||||||
|
+
|
||||||
|
+ /* parse year, month, day, hour, minute */
|
||||||
|
+ CHECK( x509_parse_int( p, yearlen, &time->year ) );
|
||||||
|
+ if (yearlen == 2)
|
||||||
|
+ {
|
||||||
|
+ if (time->year < 50)
|
||||||
|
+ time->year += 100;
|
||||||
|
+ time->year += 1900;
|
||||||
|
+ }
|
||||||
|
+ CHECK( x509_parse_int( p, 2, &time->mon ) );
|
||||||
|
+ CHECK( x509_parse_int( p, 2, &time->day ) );
|
||||||
|
+ CHECK( x509_parse_int( p, 2, &time->hour ) );
|
||||||
|
+ CHECK( x509_parse_int( p, 2, &time->min ) );
|
||||||
|
+
|
||||||
|
+ /* parse seconds if present */
|
||||||
|
+ if (len >= 2 && **p >= '0' && **p <= '9')
|
||||||
|
+ {
|
||||||
|
+ CHECK( x509_parse_int( p, 2, &time->sec ) );
|
||||||
|
+ len -= 2;
|
||||||
|
+ }
|
||||||
|
+ else
|
||||||
|
+ {
|
||||||
|
+#if defined(POLARSSL_RELAXED_X509_DATE)
|
||||||
|
+ /* if relaxed mode, allow seconds to be absent */
|
||||||
|
+ time->sec = 0;
|
||||||
|
+#else
|
||||||
|
+ return POLARSSL_ERR_X509_INVALID_DATE;
|
||||||
|
+#endif
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* parse trailing 'Z' if present */
|
||||||
|
+ if (len == 1 && **p == 'Z')
|
||||||
|
+ {
|
||||||
|
+ (*p)++;
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+#if defined(POLARSSL_RELAXED_X509_DATE)
|
||||||
|
+ /* if relaxed mode, allow timezone to be present */
|
||||||
|
+ else if (len == 5 && **p == '+')
|
||||||
|
+ {
|
||||||
|
+ int tz; /* throwaway timezone */
|
||||||
|
+ (*p)++;
|
||||||
|
+ CHECK( x509_parse_int( p, 4, &tz ) );
|
||||||
|
+ return 0;
|
||||||
|
+ }
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+ /* okay if no trailing 'Z' or timezone specified */
|
||||||
|
+ else if (len == 0)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ else
|
||||||
|
+ return POLARSSL_ERR_X509_INVALID_DATE;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
* Time ::= CHOICE {
|
||||||
|
* utcTime UTCTime,
|
||||||
|
* generalTime GeneralizedTime }
|
||||||
|
@@ -515,20 +582,7 @@
|
||||||
|
if( ret != 0 )
|
||||||
|
return( POLARSSL_ERR_X509_INVALID_DATE + ret );
|
||||||
|
|
||||||
|
- CHECK( x509_parse_int( p, 2, &time->year ) );
|
||||||
|
- CHECK( x509_parse_int( p, 2, &time->mon ) );
|
||||||
|
- CHECK( x509_parse_int( p, 2, &time->day ) );
|
||||||
|
- CHECK( x509_parse_int( p, 2, &time->hour ) );
|
||||||
|
- CHECK( x509_parse_int( p, 2, &time->min ) );
|
||||||
|
- if( len > 10 )
|
||||||
|
- CHECK( x509_parse_int( p, 2, &time->sec ) );
|
||||||
|
- if( len > 12 && *(*p)++ != 'Z' )
|
||||||
|
- return( POLARSSL_ERR_X509_INVALID_DATE );
|
||||||
|
-
|
||||||
|
- time->year += 100 * ( time->year < 50 );
|
||||||
|
- time->year += 1900;
|
||||||
|
-
|
||||||
|
- return( 0 );
|
||||||
|
+ return x509_parse_time(p, len, 2, time);
|
||||||
|
}
|
||||||
|
else if( tag == ASN1_GENERALIZED_TIME )
|
||||||
|
{
|
||||||
|
@@ -538,17 +592,7 @@
|
||||||
|
if( ret != 0 )
|
||||||
|
return( POLARSSL_ERR_X509_INVALID_DATE + ret );
|
||||||
|
|
||||||
|
- CHECK( x509_parse_int( p, 4, &time->year ) );
|
||||||
|
- CHECK( x509_parse_int( p, 2, &time->mon ) );
|
||||||
|
- CHECK( x509_parse_int( p, 2, &time->day ) );
|
||||||
|
- CHECK( x509_parse_int( p, 2, &time->hour ) );
|
||||||
|
- CHECK( x509_parse_int( p, 2, &time->min ) );
|
||||||
|
- if( len > 12 )
|
||||||
|
- CHECK( x509_parse_int( p, 2, &time->sec ) );
|
||||||
|
- if( len > 14 && *(*p)++ != 'Z' )
|
||||||
|
- return( POLARSSL_ERR_X509_INVALID_DATE );
|
||||||
|
-
|
||||||
|
- return( 0 );
|
||||||
|
+ return x509_parse_time(p, len, 4, time);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return( POLARSSL_ERR_X509_INVALID_DATE +
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
ver=1.2.7
|
||||||
|
src=~/src/mac/polarssl-$ver
|
||||||
|
rm -rf polarssl-$ver polarssl-$ver.new
|
||||||
|
tar xfz $DL/polarssl-$ver-gpl.tgz
|
||||||
|
cp -a polarssl-$ver polarssl-$ver.new
|
||||||
|
cd polarssl-$ver.new
|
||||||
|
cp $src/include/polarssl/bn_mul.h include/polarssl/
|
||||||
|
cp $src/library/bignum.c library/
|
||||||
|
#cp $src/library/mpi_mul_hlp.c library/
|
||||||
|
#cp $src/library/CMakeLists.txt library/
|
||||||
|
cd ..
|
||||||
|
diff -uNr polarssl-$ver polarssl-$ver.new
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
Make the ciphersuites array argument to ssl_set_ciphersuites const.
|
||||||
|
This should be done to assure callers that PolarSSL doesn't intend
|
||||||
|
to modify this array (which it apparently doesn't).
|
||||||
|
|
||||||
|
diff -ur polarssl-1.1.1/include/polarssl/ssl.h polarssl-1.1.1.new/include/polarssl/ssl.h
|
||||||
|
--- polarssl-1.1.1/include/polarssl/ssl.h 2012-01-23 02:57:38.000000000 -0700
|
||||||
|
+++ polarssl-1.1.1.new/include/polarssl/ssl.h 2012-03-14 02:46:30.315215130 -0600
|
||||||
|
@@ -306,7 +306,7 @@
|
||||||
|
sha1_context fin_sha1; /*!< Finished SHA-1 checksum */
|
||||||
|
|
||||||
|
int do_crypt; /*!< en(de)cryption flag */
|
||||||
|
- int *ciphersuites; /*!< allowed ciphersuites */
|
||||||
|
+ const int *ciphersuites; /*!< allowed ciphersuites */
|
||||||
|
size_t pmslen; /*!< premaster length */
|
||||||
|
unsigned int keylen; /*!< symmetric key length */
|
||||||
|
size_t minlen; /*!< min. ciphertext length */
|
||||||
|
@@ -495,7 +495,7 @@
|
||||||
|
* \param ssl SSL context
|
||||||
|
* \param ciphersuites 0-terminated list of allowed ciphersuites
|
||||||
|
*/
|
||||||
|
-void ssl_set_ciphersuites( ssl_context *ssl, int *ciphersuites );
|
||||||
|
+void ssl_set_ciphersuites( ssl_context *ssl, const int *ciphersuites );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set the data required to verify peer certificate
|
||||||
|
diff -ur polarssl-1.1.1/library/ssl_tls.c polarssl-1.1.1.new/library/ssl_tls.c
|
||||||
|
--- polarssl-1.1.1/library/ssl_tls.c 2012-01-23 02:57:38.000000000 -0700
|
||||||
|
+++ polarssl-1.1.1.new/library/ssl_tls.c 2012-03-14 02:47:10.830001668 -0600
|
||||||
|
@@ -1838,7 +1838,7 @@
|
||||||
|
ssl->session = session;
|
||||||
|
}
|
||||||
|
|
||||||
|
-void ssl_set_ciphersuites( ssl_context *ssl, int *ciphersuites )
|
||||||
|
+void ssl_set_ciphersuites( ssl_context *ssl, const int *ciphersuites )
|
||||||
|
{
|
||||||
|
ssl->ciphersuites = ciphersuites;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
This fixes an issue where the cipher.h header doesn't compile when included
|
||||||
|
by C++ code, as C++ is more strict than C about implicit enum casts.
|
||||||
|
|
||||||
|
diff -ur polarssl-1.1.1/include/polarssl/cipher.h /home/james/polarssl-1.1.1/include/polarssl/cipher.h
|
||||||
|
--- polarssl-1.1.1/include/polarssl/cipher.h 2011-11-15 08:38:45.000000000 -0700
|
||||||
|
+++ /home/james/polarssl-1.1.1/include/polarssl/cipher.h 2012-03-12 17:31:12.279631469 -0600
|
||||||
|
@@ -313,7 +313,7 @@
|
||||||
|
static inline cipher_type_t cipher_get_type( const cipher_context_t *ctx )
|
||||||
|
{
|
||||||
|
if( NULL == ctx || NULL == ctx->cipher_info )
|
||||||
|
- return 0;
|
||||||
|
+ return POLARSSL_CIPHER_NONE;
|
||||||
|
|
||||||
|
return ctx->cipher_info->type;
|
||||||
|
}
|
||||||
@@ -0,0 +1,181 @@
|
|||||||
|
This patch allows the caller to create a proxy object that can be used
|
||||||
|
in place of a private key. The proxy object must define sign and
|
||||||
|
decrypt methods. This functionality is similar to that provided by
|
||||||
|
POLARSSL_PKCS11_C except that it can accomodate any arbitrary
|
||||||
|
implementation of external private keys, not only that provided by
|
||||||
|
the PKCS#11 helper library.
|
||||||
|
|
||||||
|
This is necessary to allow PolarSSL to interact with certificate/key
|
||||||
|
stores on many different platforms that don't natively support
|
||||||
|
PKCS#11 such as Mac (uses Keychain API), Windows (uses CryptoAPI),
|
||||||
|
and Android (android.security.KeyChain).
|
||||||
|
|
||||||
|
In the basic usage model, the library is built with POLARSSL_PKCS11_C
|
||||||
|
and POLARSSL_GENERIC_EXTERNAL_PRIVATE_KEY. Doing this causes the
|
||||||
|
pkcs11_context object to become an interface to any arbitrary
|
||||||
|
external private key implementation that defines sign and decrypt
|
||||||
|
methods. Note that in this configuration, the PKCS#11 helper library
|
||||||
|
(libpkcs11-helper) is not used.
|
||||||
|
|
||||||
|
When POLARSSL_PKCS11_C is defined in the absence of
|
||||||
|
POLARSSL_GENERIC_EXTERNAL_PRIVATE_KEY, the pkcs11_context object
|
||||||
|
reverts to its previous implementation, where it becomes a
|
||||||
|
connector to a certificate/private-key context in the PKCS#11 helper
|
||||||
|
library.
|
||||||
|
|
||||||
|
diff -ur polarssl-1.1.1.orig/include/polarssl/config.h polarssl-1.1.1/include/polarssl/config.h
|
||||||
|
--- polarssl-1.1.1.orig/include/polarssl/config.h 2011-12-22 03:06:27.000000000 -0700
|
||||||
|
+++ polarssl-1.1.1/include/polarssl/config.h 2012-03-14 02:31:04.000000000 -0600
|
||||||
|
@@ -531,10 +531,26 @@
|
||||||
|
*
|
||||||
|
* This module is required for SSL/TLS PKCS #11 smartcard support.
|
||||||
|
* Requires the presence of the PKCS#11 helper library (libpkcs11-helper)
|
||||||
|
+ * unless POLARSSL_GENERIC_EXTERNAL_PRIVATE_KEY is also defined.
|
||||||
|
+ *
|
||||||
|
#define POLARSSL_PKCS11_C
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
+ * \def POLARSSL_GENERIC_EXTERNAL_PRIVATE_KEY
|
||||||
|
+ *
|
||||||
|
+ * Enable support for generic external private key implementations.
|
||||||
|
+ *
|
||||||
|
+ * Module: library/ssl_srv.c
|
||||||
|
+ * Caller: library/ssl_cli.c
|
||||||
|
+ * library/ssl_srv.c
|
||||||
|
+ *
|
||||||
|
+ * Requires: POLARSSL_PKCS11_C
|
||||||
|
+ *
|
||||||
|
+#define POLARSSL_GENERIC_EXTERNAL_PRIVATE_KEY
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
* \def POLARSSL_RSA_C
|
||||||
|
*
|
||||||
|
* Enable the RSA public-key cryptosystem.
|
||||||
|
diff -ur polarssl-1.1.1.orig/include/polarssl/pkcs11.h polarssl-1.1.1/include/polarssl/pkcs11.h
|
||||||
|
--- polarssl-1.1.1.orig/include/polarssl/pkcs11.h 2011-11-18 07:26:47.000000000 -0700
|
||||||
|
+++ polarssl-1.1.1/include/polarssl/pkcs11.h 2012-03-14 02:28:34.000000000 -0600
|
||||||
|
@@ -35,6 +35,95 @@
|
||||||
|
|
||||||
|
#include "x509.h"
|
||||||
|
|
||||||
|
+#if defined(POLARSSL_GENERIC_EXTERNAL_PRIVATE_KEY)
|
||||||
|
+
|
||||||
|
+/* inline preamble */
|
||||||
|
+#if defined(_MSC_VER) && !defined(inline)
|
||||||
|
+#define inline _inline
|
||||||
|
+#else
|
||||||
|
+#if defined(__ARMCC_VERSION) && !defined(inline)
|
||||||
|
+#define inline __inline
|
||||||
|
+#endif /* __ARMCC_VERSION */
|
||||||
|
+#endif /*_MSC_VER */
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * This object is a reference to an external private key,
|
||||||
|
+ * and can be used in place of a concrete private key.
|
||||||
|
+ */
|
||||||
|
+typedef struct _pkcs11_context {
|
||||||
|
+ void *parameter; /** user-defined parameter */
|
||||||
|
+ int len; /** private key length in bytes */
|
||||||
|
+
|
||||||
|
+ /** user-defined decrypt method, see pkcs11_decrypt doc below */
|
||||||
|
+ int (*f_decrypt)( struct _pkcs11_context *ctx,
|
||||||
|
+ int mode, size_t *olen,
|
||||||
|
+ const unsigned char *input,
|
||||||
|
+ unsigned char *output,
|
||||||
|
+ unsigned int output_max_len );
|
||||||
|
+
|
||||||
|
+ /** user-defined sign method, see pkcs11_sign doc below */
|
||||||
|
+ int (*f_sign)( struct _pkcs11_context *ctx,
|
||||||
|
+ int mode,
|
||||||
|
+ int hash_id,
|
||||||
|
+ unsigned int hashlen,
|
||||||
|
+ const unsigned char *hash,
|
||||||
|
+ unsigned char *sig );
|
||||||
|
+
|
||||||
|
+} pkcs11_context;
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * \brief Do an RSA private key decrypt, then remove the message padding
|
||||||
|
+ *
|
||||||
|
+ * \param ctx PKCS #11 context
|
||||||
|
+ * \param mode must be RSA_PRIVATE, for compatibility with rsa.c's signature
|
||||||
|
+ * \param input buffer holding the encrypted data
|
||||||
|
+ * \param output buffer that will hold the plaintext
|
||||||
|
+ * \param olen will contain the plaintext length
|
||||||
|
+ * \param output_max_len maximum length of the output buffer
|
||||||
|
+ *
|
||||||
|
+ * \return 0 if successful, or an POLARSSL_ERR_RSA_XXX error code
|
||||||
|
+ *
|
||||||
|
+ * \note The output buffer must be as large as the size
|
||||||
|
+ * of ctx->N (eg. 128 bytes if RSA-1024 is used) otherwise
|
||||||
|
+ * an error is thrown.
|
||||||
|
+ */
|
||||||
|
+static inline int pkcs11_decrypt( pkcs11_context *ctx,
|
||||||
|
+ int mode, size_t *olen,
|
||||||
|
+ const unsigned char *input,
|
||||||
|
+ unsigned char *output,
|
||||||
|
+ unsigned int output_max_len )
|
||||||
|
+{
|
||||||
|
+ return (*ctx->f_decrypt)(ctx, mode, olen, input, output, output_max_len);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/**
|
||||||
|
+ * \brief Do a private RSA to sign a message digest
|
||||||
|
+ *
|
||||||
|
+ * \param ctx PKCS #11 context
|
||||||
|
+ * \param mode must be RSA_PRIVATE, for compatibility with rsa.c's signature
|
||||||
|
+ * \param hash_id SIG_RSA_RAW, SIG_RSA_MD{2,4,5} or SIG_RSA_SHA{1,224,256,384,512}
|
||||||
|
+ * \param hashlen message digest length (for SIG_RSA_RAW only)
|
||||||
|
+ * \param hash buffer holding the message digest
|
||||||
|
+ * \param sig buffer that will hold the ciphertext
|
||||||
|
+ *
|
||||||
|
+ * \return 0 if the signing operation was successful,
|
||||||
|
+ * or an POLARSSL_ERR_RSA_XXX error code
|
||||||
|
+ *
|
||||||
|
+ * \note The "sig" buffer must be as large as the size
|
||||||
|
+ * of ctx->N (eg. 128 bytes if RSA-1024 is used).
|
||||||
|
+ */
|
||||||
|
+static inline int pkcs11_sign( pkcs11_context *ctx,
|
||||||
|
+ int mode,
|
||||||
|
+ int hash_id,
|
||||||
|
+ unsigned int hashlen,
|
||||||
|
+ const unsigned char *hash,
|
||||||
|
+ unsigned char *sig )
|
||||||
|
+{
|
||||||
|
+ return (*ctx->f_sign)(ctx, mode, hash_id, hashlen, hash, sig);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#else
|
||||||
|
+
|
||||||
|
#include <pkcs11-helper-1.0/pkcs11h-certificate.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
@@ -121,6 +210,8 @@
|
||||||
|
const unsigned char *hash,
|
||||||
|
unsigned char *sig );
|
||||||
|
|
||||||
|
+#endif /* POLARSSL_GENERIC_EXTERNAL_PRIVATE_KEY */
|
||||||
|
+
|
||||||
|
#endif /* POLARSSL_PKCS11_C */
|
||||||
|
|
||||||
|
#endif /* POLARSSL_PKCS11_H */
|
||||||
|
diff -ur polarssl-1.1.1.orig/library/pkcs11.c polarssl-1.1.1/library/pkcs11.c
|
||||||
|
--- polarssl-1.1.1.orig/library/pkcs11.c 2011-04-24 02:57:21.000000000 -0600
|
||||||
|
+++ polarssl-1.1.1/library/pkcs11.c 2012-03-14 02:28:22.000000000 -0600
|
||||||
|
@@ -29,7 +29,7 @@
|
||||||
|
|
||||||
|
#include "polarssl/pkcs11.h"
|
||||||
|
|
||||||
|
-#if defined(POLARSSL_PKCS11_C)
|
||||||
|
+#if defined(POLARSSL_PKCS11_C) && !defined(POLARSSL_GENERIC_EXTERNAL_PRIVATE_KEY)
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
@@ -235,4 +235,4 @@
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
-#endif /* defined(POLARSSL_PKCS11_C) */
|
||||||
|
+#endif /* defined(POLARSSL_PKCS11_C) && !defined(POLARSSL_GENERIC_EXTERNAL_PRIVATE_KEY) */
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
diff -ur polarssl-1.1.3/library/ssl_tls.c polarssl-1.1.3.jy/library/ssl_tls.c
|
||||||
|
--- polarssl-1.1.3/library/ssl_tls.c 2012-04-20 07:33:14.000000000 -0600
|
||||||
|
+++ polarssl-1.1.3.jy/library/ssl_tls.c 2012-05-29 09:12:11.687371794 -0600
|
||||||
|
@@ -785,7 +785,7 @@
|
||||||
|
/*
|
||||||
|
* Always compute the MAC (RFC4346, CBCTIME).
|
||||||
|
*/
|
||||||
|
- if( ssl->in_msglen <= ssl->maclen + padlen )
|
||||||
|
+ if( ssl->in_msglen < ssl->maclen + padlen )
|
||||||
|
{
|
||||||
|
SSL_DEBUG_MSG( 1, ( "msglen (%d) < maclen (%d) + padlen (%d)",
|
||||||
|
ssl->in_msglen, ssl->maclen, padlen ) );
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
Patch to 1.1.4 to allow X509 v3 trust extensions.
|
||||||
|
--------------------------------------------------
|
||||||
|
Index: x509parse.c
|
||||||
|
===================================================================
|
||||||
|
--- x509parse.c (revision 1322)
|
||||||
|
+++ x509parse.c (working copy)
|
||||||
|
@@ -1134,7 +1134,7 @@
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
size_t len;
|
||||||
|
- unsigned char *p, *end;
|
||||||
|
+ unsigned char *p, *end, *crt_end;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check for valid input
|
||||||
|
@@ -1168,13 +1168,14 @@
|
||||||
|
return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT );
|
||||||
|
}
|
||||||
|
|
||||||
|
- if( len != (size_t) ( end - p ) )
|
||||||
|
+ if( len > (size_t) ( end - p ) )
|
||||||
|
{
|
||||||
|
x509_free( crt );
|
||||||
|
return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT +
|
||||||
|
POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
|
||||||
|
}
|
||||||
|
-
|
||||||
|
+ crt_end = p + len;
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* TBSCertificate ::= SEQUENCE {
|
||||||
|
*/
|
||||||
|
@@ -1344,7 +1345,7 @@
|
||||||
|
POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
|
||||||
|
}
|
||||||
|
|
||||||
|
- end = crt->raw.p + crt->raw.len;
|
||||||
|
+ end = crt_end;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* signatureAlgorithm AlgorithmIdentifier,
|
||||||
|
|
||||||
|
----------------------------------------------------
|
||||||
|
End of patch file
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
if [ -z "$O3" ]; then
|
||||||
|
echo O3 var must point to ovpn3 tree
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if [ -z "$TARGET" ]; then
|
||||||
|
echo TARGET var must be defined
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -z "$DL" ] && DL=~/Downloads
|
||||||
|
|
||||||
|
# source vars
|
||||||
|
. $O3/core/vars/vars-${TARGET}
|
||||||
|
. $O3/core/deps/lib-versions
|
||||||
|
|
||||||
|
[ "$GCC_CMD" ] && export CC=$GCC_CMD
|
||||||
|
[ "$GPP_CMD" ] && export CXX=$GPP_CMD
|
||||||
|
[ "$LD_CMD" ] && export LD=$LD_CMD
|
||||||
|
[ "$AR_CMD" ] && export AR=$AR_CMD
|
||||||
|
[ "$RANLIB_CMD" ] && export RANLIB=$RANLIB_CMD
|
||||||
|
|
||||||
|
case $PLATFORM in
|
||||||
|
android*)
|
||||||
|
echo PLATFORM android
|
||||||
|
host=arm
|
||||||
|
target=arm
|
||||||
|
;;
|
||||||
|
ios*)
|
||||||
|
echo PLATFORM ios
|
||||||
|
host="x86_64-apple-darwin"
|
||||||
|
target=arm
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
host=""
|
||||||
|
target=""
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if [ "$target" ]; then
|
||||||
|
targ_opt="--target=$target"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$host" ]; then
|
||||||
|
host_opt="--host=$host"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$NO_WIPE" != "1" ]; then
|
||||||
|
rm -rf $SNAPPY_VERSION
|
||||||
|
tar xfz $DL/$SNAPPY_VERSION.tar.gz
|
||||||
|
fi
|
||||||
|
|
||||||
|
DIST=$(pwd)/snappy/snappy-$PLATFORM
|
||||||
|
rm -rf $DIST
|
||||||
|
mkdir -p $DIST
|
||||||
|
cd $SNAPPY_VERSION
|
||||||
|
echo 'OPTIONS' CC=$CC LD=$LD AR=$AR RANLIB=$RANLIB host_opt=$host_opt targ_opt=$targ_opt
|
||||||
|
export CFLAGS="$PLATFORM_FLAGS $OTHER_COMPILER_FLAGS $LIB_OPT_LEVEL $LIB_FPIC"
|
||||||
|
echo 'CFLAGS' $CFLAGS
|
||||||
|
export CXXFLAGS="$CFLAGS $CXX_COMPILER_FLAGS"
|
||||||
|
./configure --prefix=$DIST $host_opt $targ_opt --enable-static --disable-shared
|
||||||
|
make
|
||||||
|
make install
|
||||||
|
exit 0
|
||||||
@@ -0,0 +1,198 @@
|
|||||||
|
OpenVPN Protocol extensions
|
||||||
|
2015-01-06
|
||||||
|
|
||||||
|
1. DATA_V2 opcode with 24-bit peer ID
|
||||||
|
|
||||||
|
* The DATA_V2 opcode is 9.
|
||||||
|
* The DATA_V2 opcode/key_id byte is followed by 3 additional
|
||||||
|
(network endian) bytes indicating the peer ID.
|
||||||
|
* If a 4-byte DATA_V2 header is passed through ntohl,
|
||||||
|
the resulting high 8 bits will be the DATA_V2 opcode/key_id,
|
||||||
|
and the lower 24 bits will be the peer ID.
|
||||||
|
* A disabled peer ID is denoted by 0xFFFFFF.
|
||||||
|
* Server tells the client to use DATA_V2/peer_id by pushing
|
||||||
|
the directive "peer-id ID" where ID is a decimal integer
|
||||||
|
in the range [-1, 16777215]. Setting the peer ID to -1
|
||||||
|
transmits DATA_V2 packets with the peer ID field set to
|
||||||
|
0xFFFFFF. Setting the peer_id to -1 is the same as
|
||||||
|
setting it to 16777215 (i.e. 0xFFFFFF).
|
||||||
|
* Client never transmits DATA_V2 packets unless the server
|
||||||
|
has pushed a "peer-id" directive.
|
||||||
|
* Server never pushes a "peer-id" directive unless the
|
||||||
|
client has indicated its support for DATA_V2 by
|
||||||
|
including "IV_PROTO=2" in the peer info data.
|
||||||
|
* When DATA_V2 is used for "float" functionality, the server
|
||||||
|
must perform the following checks before allowing
|
||||||
|
a client to float, i.e. to assume a new source address.
|
||||||
|
(a) verify integrity (HMAC or GCM auth tag, replay
|
||||||
|
protection, etc.) of the DATA_V2 packet, and
|
||||||
|
(b) ensure that the float doesn't clobber a pre-existing
|
||||||
|
client (i.e. if the address floated to is already
|
||||||
|
owned by another client) unless it can be verified
|
||||||
|
that the pre-existing client is a previous instance
|
||||||
|
of the floating client.
|
||||||
|
|
||||||
|
2. AEAD mode
|
||||||
|
|
||||||
|
To support AEAD crypto modes such as AES-GCM, some protocol
|
||||||
|
changes are in order. AES-GCM, for example, requires a 12
|
||||||
|
byte unique nonce for every packet. I would propose that 4
|
||||||
|
bytes be taken from the Packet ID which increments for every
|
||||||
|
packet and therefore provides uniqueness. The remaining 8
|
||||||
|
bytes would be derived from the random key material that would
|
||||||
|
normally be used to key the HMAC key. This is possible since
|
||||||
|
AEAD modes use a combined key for encryption and integrity
|
||||||
|
checking, therefore the random key material for HMAC is
|
||||||
|
unused and can be repurposed as an AEAD nonce source. The 8
|
||||||
|
byte nonce component derived from the HMAC keying material
|
||||||
|
would remain constant for a given Key State. Only the 4 byte
|
||||||
|
Packet ID would increment for each packet. Because AEAD
|
||||||
|
encryption can be compromised if the nonce ever repeats for
|
||||||
|
a given key, the implementation MUST disable encryption
|
||||||
|
for a key if the 32-bit packet ID wraps. In practical usage,
|
||||||
|
renegotiation usually preempts wrapping, so the
|
||||||
|
disable-encryption-on-wrap feature is a failsafe.
|
||||||
|
|
||||||
|
AEAD Nonce:
|
||||||
|
|
||||||
|
[ Packet ID ] [ HMAC keying material ]
|
||||||
|
[ 4 bytes ] [ 8 bytes ]
|
||||||
|
[ AEAD nonce total: 12 bytes ]
|
||||||
|
|
||||||
|
TLS wire protocol:
|
||||||
|
|
||||||
|
[ DATA_V2 opcode ] [ Packet ID ] [ AEAD Auth tag ] [ ciphertext ]
|
||||||
|
[ 4 bytes ] [ 4 bytes ] [ 16 bytes ]
|
||||||
|
[ AEAD additional data (AD) ]
|
||||||
|
|
||||||
|
Static Key wire protocol:
|
||||||
|
|
||||||
|
[ DATA_V2 opcode ] [ Packet ID ] [ Nonce tail (random) ] [ AEAD Auth tag ] [ ciphertext ]
|
||||||
|
[ AEAD nonce ]
|
||||||
|
[ 4 bytes ] [ 8 bytes ] [ 4 bytes ] [ 16 bytes ]
|
||||||
|
[ AEAD additional data (AD) ]
|
||||||
|
|
||||||
|
Note that the AEAD additional data (AD) includes all data
|
||||||
|
preceding the AEAD Auth tag including the DATA_V2/peer_id
|
||||||
|
opcode and packet ID.
|
||||||
|
|
||||||
|
Also, note that because the HMAC keying material used to derive
|
||||||
|
the last 8 bytes of the AEAD nonce is negotiated once per key
|
||||||
|
as part of the control channel handshake, we can omit it from the
|
||||||
|
data channel packets, thereby saving 8 bytes per packet. So
|
||||||
|
only the 4-byte Packet ID component of the nonce must be
|
||||||
|
transmitted with every packet.
|
||||||
|
|
||||||
|
When negotiating AEAD mode, the client indicates its support
|
||||||
|
of AES-128-GCM, AES-192-GCM, and AES-192-GCM by including:
|
||||||
|
|
||||||
|
IV_NCP=2
|
||||||
|
|
||||||
|
in the peer info string (NCP stands for Negotiable Crypto
|
||||||
|
Parameters).
|
||||||
|
|
||||||
|
When the IV_NCP value is 2 or higher, it indicates that
|
||||||
|
the server may push an AEAD "cipher" directive, e.g.:
|
||||||
|
|
||||||
|
push "cipher AES-128-GCM"
|
||||||
|
|
||||||
|
In the future, the IV_NCP value (2 in the current
|
||||||
|
implementation) may be increased to indicate the
|
||||||
|
availability of additional negotiable ciphers.
|
||||||
|
|
||||||
|
3. Compression V2
|
||||||
|
|
||||||
|
I have observed that compression in many cases, even when
|
||||||
|
enabled, often does not produce packet size reduction
|
||||||
|
because much of the packet data typically generated by web
|
||||||
|
sessions is already compressed. Further, the single byte that
|
||||||
|
precedes the packet and indicates whether or not compression
|
||||||
|
occurred has the unfortunate side effect of misaligning the IP
|
||||||
|
packet in cases where compression did not occur. To remedy this,
|
||||||
|
I propose a Compression V2 header that is optimized for the
|
||||||
|
case where compression does not occur.
|
||||||
|
|
||||||
|
a. No compression occurred and first byte of IP/Ethernet packet
|
||||||
|
is NOT 0x50 (0 bytes of overhead and maintains alignment):
|
||||||
|
|
||||||
|
[ uncompressed IP/Ethernet packet ]
|
||||||
|
|
||||||
|
b. No compression occurred and first byte of IP/Ethernet packet
|
||||||
|
is 0x50 (2 bytes of overhead but unlikely since no known
|
||||||
|
IP packet can begin with 0x50):
|
||||||
|
|
||||||
|
[ 0x50 ] [ 0x00 ] [ uncompressed IP/Ethernet packet ]
|
||||||
|
|
||||||
|
c. Compression occurred (2 bytes of overhead):
|
||||||
|
|
||||||
|
[ 0x50 ] [ compression Alg ID byte ] [ compressed IP/Ethernet packet ]
|
||||||
|
|
||||||
|
Compression Alg ID is one-byte algorithm identifier
|
||||||
|
for LZ4 (0x1), LZO (0x2), or Snappy (0x3).
|
||||||
|
|
||||||
|
This approach has several beneficial effects:
|
||||||
|
|
||||||
|
1. In the common case where compression does not occur, no
|
||||||
|
compression op is required, therefore there is zero overhead.
|
||||||
|
|
||||||
|
2. When compression does not occur, the IP/Ethernet packet
|
||||||
|
alignment is retained.
|
||||||
|
|
||||||
|
3. This technique does not require any byte swapping with
|
||||||
|
the tail of the packet which can potentially incur an
|
||||||
|
expensive cache miss.
|
||||||
|
|
||||||
|
When negotiating Compression V2 mode, the client indicates its
|
||||||
|
support by including the following in the peer info string:
|
||||||
|
|
||||||
|
IV_LZ4v2=1 -> LZ4 compression available in V2 format
|
||||||
|
IV_COMP_STUBv2=1 -> stub compression available in V2 format
|
||||||
|
(i.e. disable compression but still
|
||||||
|
retain compression framing)
|
||||||
|
|
||||||
|
In response, the server can push to the client:
|
||||||
|
|
||||||
|
push "compress lz4-v2" -> enable LZ4 compression in V2 format
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
push "compress stub-v2" -> disable compression but retain
|
||||||
|
compression framing in V2 format
|
||||||
|
|
||||||
|
4. TCP nonlinear mode
|
||||||
|
|
||||||
|
The OpenVPN 2.x packet ID and replay protection code, when running
|
||||||
|
in TCP mode, requires that the packet ID follows a linearly
|
||||||
|
incrementing sequence, i.e. 1, 2, 2, 3, ... This was a reasonable
|
||||||
|
requirement, since the reliable nature of TCP guaranteed that a
|
||||||
|
linear sequence of packet IDs transmitted by the sender would be
|
||||||
|
received in the same order by the receiver.
|
||||||
|
|
||||||
|
However, recent work has shown that multithreaded OpenVPN servers
|
||||||
|
may not be able to guarantee TCP packet ID linearity (on the
|
||||||
|
transmit side) without incurring a performance penalty. This
|
||||||
|
is because the packet ID for transmitted packets must be allocated
|
||||||
|
before the packet is encrypted, while a multithreaded OpenVPN server
|
||||||
|
might be concurrently encrypting and transmitting multiple packets
|
||||||
|
using different threads, where the order that the threads complete
|
||||||
|
encryption and transmit the packet is non-deterministic. This
|
||||||
|
non-deterministic ordering of packets over the TCP session means
|
||||||
|
that the client might see out-of-order packets and a non-linear
|
||||||
|
packet ID progression, just as clients now see with UDP.
|
||||||
|
|
||||||
|
My proposed solution to the issue is to relax the Packet ID
|
||||||
|
validation on the receiver side to allow non-linear packet ID
|
||||||
|
sequences, even in TCP mode. This essentially means that the
|
||||||
|
packet ID validation logic is now the same for both UDP and TCP.
|
||||||
|
|
||||||
|
The client indicates its ability to process non-linear packet
|
||||||
|
ID sequences in TCP mode by including the following in the
|
||||||
|
peer info string:
|
||||||
|
|
||||||
|
IV_TCPNL=1 -> TCP non-linear receiver supported
|
||||||
|
|
||||||
|
When the server receives a IV_TCPNL setting of 1 from the
|
||||||
|
client, it may transmit out-of-order packets in TCP mode.
|
||||||
|
Otherwise, servers must use other means (such as using thread
|
||||||
|
synchronization primitives) to ensure strictly linear packet
|
||||||
|
ID ordering in TCP mode.
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
build
|
||||||
|
ovpncli_wrap.cxx
|
||||||
|
ovpncli_wrap.h
|
||||||
|
ovpncli.java
|
||||||
|
ovpncliJNI.java
|
||||||
|
ClientAPI_*.java
|
||||||
|
SWIGTYPE_*.java
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// TESTING_ONLY
|
||||||
|
|
||||||
|
public class Client implements OpenVPNClientThread.EventReceiver {
|
||||||
|
private OpenVPNClientThread client_thread;
|
||||||
|
|
||||||
|
public static class ConfigError extends Exception {
|
||||||
|
public ConfigError(String msg) { super(msg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class CredsUnspecifiedError extends Exception {
|
||||||
|
public CredsUnspecifiedError(String msg) { super(msg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load OpenVPN core (implements ClientAPI_OpenVPNClient) from shared library
|
||||||
|
static {
|
||||||
|
System.loadLibrary("ovpncli");
|
||||||
|
ClientAPI_OpenVPNClient.init_process();
|
||||||
|
String test = ClientAPI_OpenVPNClient.crypto_self_test();
|
||||||
|
System.out.format("CRYPTO SELF TEST: %s", test);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Client(String config_text, String username, String password) throws ConfigError, CredsUnspecifiedError {
|
||||||
|
// init client implementation object
|
||||||
|
client_thread = new OpenVPNClientThread();
|
||||||
|
|
||||||
|
// load/eval config
|
||||||
|
ClientAPI_Config config = new ClientAPI_Config();
|
||||||
|
config.setContent(config_text);
|
||||||
|
config.setCompressionMode("yes");
|
||||||
|
ClientAPI_EvalConfig ec = client_thread.eval_config(config);
|
||||||
|
if (ec.getError())
|
||||||
|
throw new ConfigError("OpenVPN config file parse error: " + ec.getMessage());
|
||||||
|
|
||||||
|
// handle creds
|
||||||
|
ClientAPI_ProvideCreds creds = new ClientAPI_ProvideCreds();
|
||||||
|
if (!ec.getAutologin())
|
||||||
|
{
|
||||||
|
if (username.length() > 0)
|
||||||
|
{
|
||||||
|
creds.setUsername(username);
|
||||||
|
creds.setPassword(password);
|
||||||
|
creds.setReplacePasswordWithSessionID(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new CredsUnspecifiedError("OpenVPN config file requires username/password but none provided");
|
||||||
|
}
|
||||||
|
client_thread.provide_creds(creds);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connect() {
|
||||||
|
// connect
|
||||||
|
client_thread.connect(this);
|
||||||
|
|
||||||
|
// wait for worker thread to exit
|
||||||
|
client_thread.wait_thread_long();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
client_thread.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void show_stats() {
|
||||||
|
int n = client_thread.stats_n();
|
||||||
|
for (int i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
String name = client_thread.stats_name(i);
|
||||||
|
long value = client_thread.stats_value(i);
|
||||||
|
if (value > 0)
|
||||||
|
System.out.format("STAT %s=%s%n", name, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void event(ClientAPI_Event event) {
|
||||||
|
boolean error = event.getError();
|
||||||
|
String name = event.getName();
|
||||||
|
String info = event.getInfo();
|
||||||
|
System.out.format("EVENT: err=%b name=%s info='%s'%n", error, name, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback to get a certificate
|
||||||
|
@Override
|
||||||
|
public void external_pki_cert_request(ClientAPI_ExternalPKICertRequest req) {
|
||||||
|
req.setError(true);
|
||||||
|
req.setErrorText("cert request failed: external PKI not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback to sign data
|
||||||
|
@Override
|
||||||
|
public void external_pki_sign_request(ClientAPI_ExternalPKISignRequest req) {
|
||||||
|
req.setError(true);
|
||||||
|
req.setErrorText("sign request failed: external PKI not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void log(ClientAPI_LogInfo loginfo) {
|
||||||
|
String text = loginfo.getText();
|
||||||
|
System.out.format("LOG: %s", text);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void done(ClientAPI_Status status) {
|
||||||
|
System.out.format("DONE ClientAPI_Status: err=%b msg='%s'%n", status.getError(), status.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean socket_protect(int socket)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean pause_on_connection_timeout()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OpenVPNClientThread.TunBuilder tun_builder_new()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// TESTING_ONLY
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
public class Main {
|
||||||
|
// utility method to read a file and return as a String
|
||||||
|
public static String readFile(String filename) throws IOException {
|
||||||
|
return readStream(new FileInputStream(filename));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String readStream(InputStream stream) throws IOException {
|
||||||
|
// No real need to close the BufferedReader/InputStreamReader
|
||||||
|
// as they're only wrapping the stream
|
||||||
|
try {
|
||||||
|
Reader reader = new BufferedReader(new InputStreamReader(stream));
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
char[] buffer = new char[4096];
|
||||||
|
int read;
|
||||||
|
while ((read = reader.read(buffer, 0, buffer.length)) > 0) {
|
||||||
|
builder.append(buffer, 0, read);
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
} finally {
|
||||||
|
// Potential issue here: if this throws an IOException,
|
||||||
|
// it will mask any others. Normally I'd use a utility
|
||||||
|
// method which would log exceptions and swallow them
|
||||||
|
stream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException, Client.ConfigError, Client.CredsUnspecifiedError {
|
||||||
|
if (args.length >= 1)
|
||||||
|
{
|
||||||
|
// load config file
|
||||||
|
String config = readFile(args[0]);
|
||||||
|
|
||||||
|
// get creds
|
||||||
|
String username = "";
|
||||||
|
String password = "";
|
||||||
|
if (args.length >= 3)
|
||||||
|
{
|
||||||
|
username = args[1];
|
||||||
|
password = args[2];
|
||||||
|
}
|
||||||
|
|
||||||
|
// instantiate client object
|
||||||
|
final Client client = new Client(config, username, password);
|
||||||
|
|
||||||
|
// catch signals
|
||||||
|
final Thread mainThread = Thread.currentThread();
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread() {
|
||||||
|
public void run() {
|
||||||
|
client.stop();
|
||||||
|
try {
|
||||||
|
mainThread.join();
|
||||||
|
}
|
||||||
|
catch (InterruptedException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// execute client session
|
||||||
|
client.connect();
|
||||||
|
|
||||||
|
// show stats before exit
|
||||||
|
client.show_stats();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
System.err.println("OpenVPN Java client");
|
||||||
|
System.err.println("Usage: java Client <client.ovpn> [username] [password]");
|
||||||
|
System.exit(2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,359 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// package OPENVPN_PACKAGE
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
public class OpenVPNClientThread extends ClientAPI_OpenVPNClient implements Runnable {
|
||||||
|
private EventReceiver parent;
|
||||||
|
private TunBuilder tun_builder;
|
||||||
|
private Thread thread;
|
||||||
|
private ClientAPI_Status m_connect_status;
|
||||||
|
private boolean connect_called = false;
|
||||||
|
|
||||||
|
private int bytes_in_index = -1;
|
||||||
|
private int bytes_out_index = -1;
|
||||||
|
|
||||||
|
// thrown if instantiator attempts to call connect more than once
|
||||||
|
public static class ConnectCalledTwice extends RuntimeException {
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface EventReceiver {
|
||||||
|
// Called with events from core
|
||||||
|
void event(ClientAPI_Event event);
|
||||||
|
|
||||||
|
// Called with log text from core
|
||||||
|
void log(ClientAPI_LogInfo loginfo);
|
||||||
|
|
||||||
|
// Called when connect() thread exits
|
||||||
|
void done(ClientAPI_Status status);
|
||||||
|
|
||||||
|
// Called to "protect" a socket from being routed through the tunnel
|
||||||
|
boolean socket_protect(int socket);
|
||||||
|
|
||||||
|
// When a connection is close to timeout, the core will call this
|
||||||
|
// method. If it returns false, the core will disconnect with a
|
||||||
|
// CONNECTION_TIMEOUT event. If true, the core will enter a PAUSE
|
||||||
|
// state.
|
||||||
|
boolean pause_on_connection_timeout();
|
||||||
|
|
||||||
|
// Callback to construct a new tun builder
|
||||||
|
TunBuilder tun_builder_new();
|
||||||
|
|
||||||
|
// Callback to get a certificate
|
||||||
|
void external_pki_cert_request(ClientAPI_ExternalPKICertRequest req);
|
||||||
|
|
||||||
|
// Callback to sign data
|
||||||
|
void external_pki_sign_request(ClientAPI_ExternalPKISignRequest req);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface TunBuilder {
|
||||||
|
// Tun builder methods.
|
||||||
|
// Methods documented in openvpn/tun/builder/base.hpp
|
||||||
|
|
||||||
|
boolean tun_builder_set_remote_address(String address, boolean ipv6);
|
||||||
|
boolean tun_builder_add_address(String address, int prefix_length, String gateway, boolean ipv6, boolean net30);
|
||||||
|
boolean tun_builder_reroute_gw(boolean ipv4, boolean ipv6, long flags);
|
||||||
|
boolean tun_builder_add_route(String address, int prefix_length, boolean ipv6);
|
||||||
|
boolean tun_builder_exclude_route(String address, int prefix_length, boolean ipv6);
|
||||||
|
boolean tun_builder_add_dns_server(String address, boolean ipv6);
|
||||||
|
boolean tun_builder_add_search_domain(String domain);
|
||||||
|
boolean tun_builder_set_mtu(int mtu);
|
||||||
|
boolean tun_builder_set_session_name(String name);
|
||||||
|
int tun_builder_establish();
|
||||||
|
void tun_builder_teardown(boolean disconnect);
|
||||||
|
}
|
||||||
|
|
||||||
|
public OpenVPNClientThread() {
|
||||||
|
final int n = stats_n();
|
||||||
|
for (int i = 0; i < n; ++i)
|
||||||
|
{
|
||||||
|
String name = stats_name(i);
|
||||||
|
if (name.equals("BYTES_IN"))
|
||||||
|
bytes_in_index = i;
|
||||||
|
if (name.equals("BYTES_OUT"))
|
||||||
|
bytes_out_index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// start connect session in worker thread
|
||||||
|
public void connect(EventReceiver parent_arg) {
|
||||||
|
if (connect_called)
|
||||||
|
throw new ConnectCalledTwice();
|
||||||
|
connect_called = true;
|
||||||
|
|
||||||
|
// direct client callbacks to parent
|
||||||
|
parent = parent_arg;
|
||||||
|
|
||||||
|
// clear status
|
||||||
|
m_connect_status = null;
|
||||||
|
|
||||||
|
// execute client in a worker thread
|
||||||
|
thread = new Thread(this, "OpenVPNClientThread");
|
||||||
|
thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for worker thread to complete; to stop thread,
|
||||||
|
// first call super stop() method then wait_thread().
|
||||||
|
// This method will give the thread one second to
|
||||||
|
// exit and will abandon it after this time.
|
||||||
|
public void wait_thread_short() {
|
||||||
|
final int wait_millisecs = 5000; // max time that we will wait for thread to exit
|
||||||
|
Thread th = thread;
|
||||||
|
if (th != null) {
|
||||||
|
try {
|
||||||
|
th.join(wait_millisecs);
|
||||||
|
}
|
||||||
|
catch (InterruptedException e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// thread failed to stop?
|
||||||
|
if (th.isAlive()) {
|
||||||
|
// abandon thread and deliver our own status object to instantiator.
|
||||||
|
ClientAPI_Status status = new ClientAPI_Status();
|
||||||
|
status.setError(true);
|
||||||
|
status.setMessage("CORE_THREAD_ABANDONED");
|
||||||
|
call_done(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for worker thread to complete; to stop thread,
|
||||||
|
// first call super stop() method then wait_thread().
|
||||||
|
// This method will wait forever for the thread to exit.
|
||||||
|
public void wait_thread_long() {
|
||||||
|
if (thread != null) {
|
||||||
|
boolean interrupted;
|
||||||
|
do {
|
||||||
|
interrupted = false;
|
||||||
|
try {
|
||||||
|
thread.join();
|
||||||
|
}
|
||||||
|
catch (InterruptedException e) {
|
||||||
|
interrupted = true;
|
||||||
|
super.stop(); // send thread a stop message
|
||||||
|
}
|
||||||
|
} while (interrupted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long bytes_in()
|
||||||
|
{
|
||||||
|
return super.stats_value(bytes_in_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long bytes_out()
|
||||||
|
{
|
||||||
|
return super.stats_value(bytes_out_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void call_done(ClientAPI_Status status)
|
||||||
|
{
|
||||||
|
EventReceiver p = finalize_thread(status);
|
||||||
|
if (p != null)
|
||||||
|
p.done(m_connect_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized EventReceiver finalize_thread(ClientAPI_Status connect_status)
|
||||||
|
{
|
||||||
|
EventReceiver p = parent;
|
||||||
|
if (p != null) {
|
||||||
|
// save thread connection status
|
||||||
|
m_connect_status = connect_status;
|
||||||
|
|
||||||
|
// disassociate client callbacks from parent
|
||||||
|
parent = null;
|
||||||
|
tun_builder = null;
|
||||||
|
thread = null;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runnable overrides
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
// Call out to core to start connection.
|
||||||
|
// Doesn't return until connection has terminated.
|
||||||
|
ClientAPI_Status status = super.connect();
|
||||||
|
call_done(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientAPI_OpenVPNClient (C++ class) overrides
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean socket_protect(int socket) {
|
||||||
|
EventReceiver p = parent;
|
||||||
|
if (p != null)
|
||||||
|
return p.socket_protect(socket);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean pause_on_connection_timeout() {
|
||||||
|
EventReceiver p = parent;
|
||||||
|
if (p != null)
|
||||||
|
return p.pause_on_connection_timeout();
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void event(ClientAPI_Event event) {
|
||||||
|
EventReceiver p = parent;
|
||||||
|
if (p != null)
|
||||||
|
p.event(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void log(ClientAPI_LogInfo loginfo) {
|
||||||
|
EventReceiver p = parent;
|
||||||
|
if (p != null)
|
||||||
|
p.log(loginfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void external_pki_cert_request(ClientAPI_ExternalPKICertRequest req) {
|
||||||
|
EventReceiver p = parent;
|
||||||
|
if (p != null)
|
||||||
|
p.external_pki_cert_request(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void external_pki_sign_request(ClientAPI_ExternalPKISignRequest req) {
|
||||||
|
EventReceiver p = parent;
|
||||||
|
if (p != null)
|
||||||
|
p.external_pki_sign_request(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TunBuilderBase (C++ class) overrides
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tun_builder_new() {
|
||||||
|
EventReceiver p = parent;
|
||||||
|
if (p != null) {
|
||||||
|
tun_builder = p.tun_builder_new();
|
||||||
|
return tun_builder != null;
|
||||||
|
} else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tun_builder_set_remote_address(String address, boolean ipv6) {
|
||||||
|
TunBuilder tb = tun_builder;
|
||||||
|
if (tb != null)
|
||||||
|
return tb.tun_builder_set_remote_address(address, ipv6);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tun_builder_add_address(String address, int prefix_length, String gateway, boolean ipv6, boolean net30) {
|
||||||
|
TunBuilder tb = tun_builder;
|
||||||
|
if (tb != null)
|
||||||
|
return tb.tun_builder_add_address(address, prefix_length, gateway, ipv6, net30);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tun_builder_reroute_gw(boolean ipv4, boolean ipv6, long flags) {
|
||||||
|
TunBuilder tb = tun_builder;
|
||||||
|
if (tb != null)
|
||||||
|
return tb.tun_builder_reroute_gw(ipv4, ipv6, flags);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tun_builder_add_route(String address, int prefix_length, int metric, boolean ipv6) {
|
||||||
|
TunBuilder tb = tun_builder;
|
||||||
|
if (tb != null)
|
||||||
|
return tb.tun_builder_add_route(address, prefix_length, ipv6);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tun_builder_exclude_route(String address, int prefix_length, int metric, boolean ipv6) {
|
||||||
|
TunBuilder tb = tun_builder;
|
||||||
|
if (tb != null)
|
||||||
|
return tb.tun_builder_exclude_route(address, prefix_length, ipv6);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tun_builder_add_dns_server(String address, boolean ipv6) {
|
||||||
|
TunBuilder tb = tun_builder;
|
||||||
|
if (tb != null)
|
||||||
|
return tb.tun_builder_add_dns_server(address, ipv6);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tun_builder_add_search_domain(String domain)
|
||||||
|
{
|
||||||
|
TunBuilder tb = tun_builder;
|
||||||
|
if (tb != null)
|
||||||
|
return tb.tun_builder_add_search_domain(domain);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tun_builder_set_mtu(int mtu) {
|
||||||
|
TunBuilder tb = tun_builder;
|
||||||
|
if (tb != null)
|
||||||
|
return tb.tun_builder_set_mtu(mtu);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tun_builder_set_session_name(String name)
|
||||||
|
{
|
||||||
|
TunBuilder tb = tun_builder;
|
||||||
|
if (tb != null)
|
||||||
|
return tb.tun_builder_set_session_name(name);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int tun_builder_establish() {
|
||||||
|
TunBuilder tb = tun_builder;
|
||||||
|
if (tb != null)
|
||||||
|
return tb.tun_builder_establish();
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tun_builder_teardown(boolean disconnect) {
|
||||||
|
TunBuilder tb = tun_builder;
|
||||||
|
if (tb != null)
|
||||||
|
tb.tun_builder_teardown(disconnect);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
#ifdef SWIGEXPORT
|
||||||
|
#define EXPORT SWIGEXPORT
|
||||||
|
#else
|
||||||
|
#define EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef OPENVPN_PACKAGE_ID
|
||||||
|
#error OPENVPN_PACKAGE_ID must be defined
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MAKE_SYM2(pkg_id, suffix) Java_ ## pkg_id ## _CPUUsage_ ## suffix
|
||||||
|
#define MAKE_SYM(pkg_id, suffix) MAKE_SYM2(pkg_id, suffix)
|
||||||
|
|
||||||
|
#define CPU_USAGE MAKE_SYM(OPENVPN_PACKAGE_ID, cpu_1usage)
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
jdouble CPU_USAGE(JNIEnv* env, jclass);
|
||||||
|
};
|
||||||
|
|
||||||
|
EXPORT jdouble CPU_USAGE(JNIEnv* env, jclass)
|
||||||
|
{
|
||||||
|
char fnbuf[64];
|
||||||
|
const pid_t pid = getpid();
|
||||||
|
double ret = 0.0;
|
||||||
|
|
||||||
|
snprintf(fnbuf, sizeof(fnbuf), "/proc/%u/stat", (unsigned int)pid);
|
||||||
|
FILE *fp = fopen(fnbuf, "r");
|
||||||
|
if (fp)
|
||||||
|
{
|
||||||
|
double user = 0.0;
|
||||||
|
double system = 0.0;
|
||||||
|
if (fscanf(fp, "%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %lf %lf", &user, &system) == 2)
|
||||||
|
ret = (user + system) / sysconf(_SC_CLK_TCK);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Native companion code for JellyBeanHack.java
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
#include <android/log.h>
|
||||||
|
|
||||||
|
#ifdef SWIGEXPORT
|
||||||
|
#define EXPORT SWIGEXPORT
|
||||||
|
#else
|
||||||
|
#define EXPORT
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef OPENVPN_PACKAGE_ID
|
||||||
|
#error OPENVPN_PACKAGE_ID must be defined
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MAKE_SYM2(pkg_id, suffix) Java_ ## pkg_id ## _JellyBeanHack_ ## suffix
|
||||||
|
#define MAKE_SYM(pkg_id, suffix) MAKE_SYM2(pkg_id, suffix)
|
||||||
|
|
||||||
|
#define RSA_SIGN_INIT MAKE_SYM(OPENVPN_PACKAGE_ID, rsa_1sign_1init)
|
||||||
|
#define RSA_SIGN MAKE_SYM(OPENVPN_PACKAGE_ID, rsa_1sign)
|
||||||
|
#define PKEY_RETAIN MAKE_SYM(OPENVPN_PACKAGE_ID, pkey_1retain)
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
jint RSA_SIGN_INIT(JNIEnv* env, jclass);
|
||||||
|
jbyteArray RSA_SIGN(JNIEnv* env, jclass, jbyteArray from, jint pkeyRef);
|
||||||
|
void PKEY_RETAIN(JNIEnv* env, jclass, jint pkeyRef);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void *RSA;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NID_md5_sha1=114,
|
||||||
|
CRYPTO_LOCK_EVP_PKEY=10,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct EVP_PKEY
|
||||||
|
{
|
||||||
|
int type;
|
||||||
|
int save_type;
|
||||||
|
int references;
|
||||||
|
void *ameth;
|
||||||
|
void *engine;
|
||||||
|
union {
|
||||||
|
RSA *rsa;
|
||||||
|
} pkey;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef int (*RSA_size_func_t)(const RSA *);
|
||||||
|
|
||||||
|
typedef int (*RSA_sign_func_t)(int type, const unsigned char *m, unsigned int m_length,
|
||||||
|
unsigned char *sigret, unsigned int *siglen, RSA *rsa);
|
||||||
|
|
||||||
|
typedef void (*ERR_print_errors_fp_func_t)(FILE *fp);
|
||||||
|
|
||||||
|
typedef int (*CRYPTO_add_lock_func_t)(int *pointer, int amount, int type, const char *file, int line);
|
||||||
|
|
||||||
|
static bool initialized;
|
||||||
|
static RSA_size_func_t RSA_size;
|
||||||
|
static RSA_sign_func_t RSA_sign;
|
||||||
|
static ERR_print_errors_fp_func_t ERR_print_errors_fp;
|
||||||
|
static CRYPTO_add_lock_func_t CRYPTO_add_lock;
|
||||||
|
|
||||||
|
inline bool callbacks_defined()
|
||||||
|
{
|
||||||
|
return RSA_size != NULL
|
||||||
|
&& RSA_sign != NULL
|
||||||
|
&& ERR_print_errors_fp != NULL
|
||||||
|
&& CRYPTO_add_lock != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT jint RSA_SIGN_INIT(JNIEnv* env, jclass)
|
||||||
|
{
|
||||||
|
if (!initialized)
|
||||||
|
{
|
||||||
|
void *handle = dlopen("libcrypto.so", RTLD_NOW);
|
||||||
|
if (handle)
|
||||||
|
{
|
||||||
|
RSA_size = (RSA_size_func_t) dlsym(handle, "RSA_size");
|
||||||
|
RSA_sign = (RSA_sign_func_t) dlsym(handle, "RSA_sign");
|
||||||
|
ERR_print_errors_fp = (ERR_print_errors_fp_func_t) dlsym(handle, "ERR_print_errors_fp");
|
||||||
|
CRYPTO_add_lock = (CRYPTO_add_lock_func_t) dlsym(handle, "CRYPTO_add_lock");
|
||||||
|
}
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
return callbacks_defined();
|
||||||
|
}
|
||||||
|
|
||||||
|
static int jni_throw(JNIEnv* env, const char* className, const char* msg)
|
||||||
|
{
|
||||||
|
jclass exceptionClass = env->FindClass(className);
|
||||||
|
|
||||||
|
if (exceptionClass == NULL) {
|
||||||
|
// ClassNotFoundException now pending
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (env->ThrowNew( exceptionClass, msg) != JNI_OK) {
|
||||||
|
// an exception, most likely OOM, will now be pending
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
env->DeleteLocalRef(exceptionClass);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT jbyteArray RSA_SIGN(JNIEnv* env, jclass, jbyteArray from, jint pkeyRef)
|
||||||
|
{
|
||||||
|
if (!callbacks_defined())
|
||||||
|
{
|
||||||
|
jni_throw(env, "java/lang/NullPointerException", "rsa_sign: OpenSSL callbacks undefined");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
|
||||||
|
if (pkey == NULL || from == NULL)
|
||||||
|
{
|
||||||
|
jni_throw(env, "java/lang/NullPointerException", "rsa_sign: from/pkey is NULL");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
jbyte* data = env->GetByteArrayElements(from, NULL);
|
||||||
|
if (data == NULL)
|
||||||
|
{
|
||||||
|
jni_throw(env, "java/lang/NullPointerException", "rsa_sign: data is NULL");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
int datalen = env->GetArrayLength(from);
|
||||||
|
|
||||||
|
unsigned int siglen;
|
||||||
|
unsigned char* sigret = new unsigned char[(*RSA_size)(pkey->pkey.rsa)];
|
||||||
|
|
||||||
|
if ((*RSA_sign)(NID_md5_sha1, (unsigned char*) data, datalen,
|
||||||
|
sigret, &siglen, pkey->pkey.rsa) <= 0)
|
||||||
|
{
|
||||||
|
jni_throw(env, "java/security/InvalidKeyException", "OpenSSL RSA_sign failed");
|
||||||
|
(*ERR_print_errors_fp)(stderr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
jbyteArray jb = env->NewByteArray(siglen);
|
||||||
|
env->SetByteArrayRegion(jb, 0, siglen, (jbyte *)sigret);
|
||||||
|
delete [] sigret;
|
||||||
|
return jb;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXPORT void PKEY_RETAIN(JNIEnv* env, jclass, jint pkeyRef)
|
||||||
|
{
|
||||||
|
EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef);
|
||||||
|
if (pkey && CRYPTO_add_lock)
|
||||||
|
{
|
||||||
|
const int newref = (*CRYPTO_add_lock)(&pkey->references, 1, CRYPTO_LOCK_EVP_PKEY, __FILE__, __LINE__);
|
||||||
|
__android_log_print(ANDROID_LOG_DEBUG, "openvpn", "pkey_retain ref=%d", newref);
|
||||||
|
}
|
||||||
|
}
|
||||||
+116
@@ -0,0 +1,116 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# generate expire time in python: time.mktime((2012, 5, 1, 0, 0, 0, 0, 0, -1))
|
||||||
|
# -DAPP_EXPIRE_TIME=1364796000 \
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ -z "$O3" ]; then
|
||||||
|
echo O3 var must point to ovpn3 tree
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd $O3/core
|
||||||
|
. vars/android-sdk-path
|
||||||
|
cd javacli
|
||||||
|
git clean -q -fXd .
|
||||||
|
|
||||||
|
if [ "$PKG" ]; then
|
||||||
|
pkg=$PKG
|
||||||
|
pkg_id_def="-DOPENVPN_PACKAGE_ID=${PKG//./_}"
|
||||||
|
else
|
||||||
|
pkg=net.openvpn.openvpn
|
||||||
|
pkg_id_def="-DOPENVPN_PACKAGE_ID=net_openvpn_openvpn"
|
||||||
|
fi
|
||||||
|
echo PACKAGE $PKG
|
||||||
|
|
||||||
|
if [ "$PT_PROXY" = "1" ] && [ -d "$O3/common" ]; then
|
||||||
|
common="-I$O3/common -DPRIVATE_TUNNEL_PROXY"
|
||||||
|
else
|
||||||
|
common=""
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo SWIG
|
||||||
|
swig -c++ -java -package $pkg -I$O3/core/client -I$O3/core ovpncli.i
|
||||||
|
|
||||||
|
# fixme: removed "android" from TARGET list due to compile failures in Asio
|
||||||
|
for TARGET in android-a8a android-a7a ; do
|
||||||
|
|
||||||
|
if [ "$DEBUG_BUILD" = "1" ]; then
|
||||||
|
. ../vars/vars-${TARGET}-dbg
|
||||||
|
vis1=""
|
||||||
|
vis2=""
|
||||||
|
opt2="$pkg_id_def $LIB_OPT_LEVEL"
|
||||||
|
else
|
||||||
|
. ../vars/vars-${TARGET}
|
||||||
|
vis1="-fvisibility=hidden"
|
||||||
|
vis2='-DSWIGEXPORT=__attribute__((visibility("default")))'
|
||||||
|
opt2="$pkg_id_def -Os"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$OPENSSL" = "1" ]; then
|
||||||
|
ssl_def="-DUSE_OPENSSL"
|
||||||
|
ssl_inc="-I$DEP_DIR/openssl/openssl-$PLATFORM/include"
|
||||||
|
ssl_lib="-lssl -lcrypto"
|
||||||
|
ssl_libdir="-L$DEP_DIR/openssl/openssl-$PLATFORM/lib"
|
||||||
|
else
|
||||||
|
ssl_def="-DUSE_MBEDTLS"
|
||||||
|
ssl_inc="-I$DEP_DIR/mbedtls/mbedtls-$PLATFORM/include"
|
||||||
|
ssl_lib="-lmbedtls"
|
||||||
|
ssl_libdir="-L$DEP_DIR/mbedtls/mbedtls-$PLATFORM/library"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo CORE $ABI
|
||||||
|
g++ \
|
||||||
|
$CXX_COMPILER_FLAGS \
|
||||||
|
$PLATFORM_FLAGS \
|
||||||
|
$LIB_OPT_LEVEL $LIB_FPIC \
|
||||||
|
-Wall -Wno-sign-compare -Wno-unused-parameter \
|
||||||
|
-Wno-unused-local-typedefs \
|
||||||
|
$vis1 \
|
||||||
|
$ssl_def \
|
||||||
|
-DUSE_ASIO \
|
||||||
|
-DASIO_STANDALONE \
|
||||||
|
-DASIO_NO_DEPRECATED \
|
||||||
|
-DHAVE_LZ4 \
|
||||||
|
-I$O3/core/client \
|
||||||
|
-I$O3/core \
|
||||||
|
$common \
|
||||||
|
-I$DEP_DIR/asio/asio/include \
|
||||||
|
$ssl_inc \
|
||||||
|
-I$DEP_DIR/lz4/lz4-$PLATFORM/include \
|
||||||
|
-c $O3/core/client/ovpncli.cpp
|
||||||
|
|
||||||
|
echo WRAP $ABI
|
||||||
|
g++ \
|
||||||
|
$CXX_COMPILER_FLAGS \
|
||||||
|
$PLATFORM_FLAGS \
|
||||||
|
$opt2 $LIB_FPIC \
|
||||||
|
-fno-strict-aliasing \
|
||||||
|
-Wall \
|
||||||
|
$vis1 $vis2 \
|
||||||
|
-I$O3/core/client \
|
||||||
|
-I$O3/core \
|
||||||
|
$common \
|
||||||
|
$ssl_libdir \
|
||||||
|
-L$DEP_DIR/lz4/lz4-$PLATFORM/lib \
|
||||||
|
ovpncli_wrap.cxx \
|
||||||
|
android/jellybean_hack.cpp \
|
||||||
|
android/cpu.cpp \
|
||||||
|
ovpncli.o \
|
||||||
|
-o libovpncli.so \
|
||||||
|
-shared -Wl,-soname,libovpncli.so \
|
||||||
|
$ssl_lib \
|
||||||
|
-llz4 \
|
||||||
|
-llog
|
||||||
|
|
||||||
|
if [ "$DEBUG_BUILD" != "1" ]; then
|
||||||
|
echo STRIP $ABI
|
||||||
|
strip libovpncli.so
|
||||||
|
fi
|
||||||
|
|
||||||
|
mkdir -p build/libs/$ABI
|
||||||
|
mv libovpncli.so build/libs/$ABI/
|
||||||
|
rm ovpncli.o
|
||||||
|
done
|
||||||
|
|
||||||
|
mv ovpncli.java ovpncliJNI.java SWIGTYPE_*.java ClientAPI_*.java build/
|
||||||
|
git clean -q -fX .
|
||||||
+95
@@ -0,0 +1,95 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Build OpenVPN 3 core on Linux as a callable module from Java:
|
||||||
|
#
|
||||||
|
# ./build-linux
|
||||||
|
# java -Djava.library.path=. Main profile.ovpn
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
if [ -z "$O3" ]; then
|
||||||
|
echo O3 var must point to ovpn3 tree
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
TARGET=linux
|
||||||
|
JINC="-I/usr/local/java/jdk1.7.0_55/include -I/usr/local/java/jdk1.7.0_55/include/linux"
|
||||||
|
|
||||||
|
cd $O3/core/javacli
|
||||||
|
git clean -q -fXd .
|
||||||
|
git clean -q -fd .
|
||||||
|
|
||||||
|
if [ "$DEBUG_BUILD" = "1" ]; then
|
||||||
|
. $O3/core/vars/vars-${TARGET}-dbg
|
||||||
|
vis1=""
|
||||||
|
vis2=""
|
||||||
|
opt2="$pkg_id_def $LIB_OPT_LEVEL"
|
||||||
|
else
|
||||||
|
. $O3/core/vars/vars-${TARGET}
|
||||||
|
vis1="-fvisibility=hidden"
|
||||||
|
vis2='-DSWIGEXPORT=__attribute__((visibility("default")))'
|
||||||
|
opt2="$pkg_id_def -Os"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$OPENSSL" = "1" ]; then
|
||||||
|
ssl_def="-DUSE_OPENSSL"
|
||||||
|
ssl_inc="-I$DEP_DIR/openssl/openssl-$PLATFORM/include"
|
||||||
|
ssl_lib="-lssl -lcrypto"
|
||||||
|
ssl_libdir="-L$DEP_DIR/openssl/openssl-$PLATFORM/lib"
|
||||||
|
else
|
||||||
|
ssl_def="-DUSE_MBEDTLS"
|
||||||
|
ssl_inc="-I$DEP_DIR/mbedtls/mbedtls-$PLATFORM/include"
|
||||||
|
ssl_lib="-lmbedtls"
|
||||||
|
ssl_libdir="-L$DEP_DIR/mbedtls/mbedtls-$PLATFORM/library"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo SWIG
|
||||||
|
swig -c++ -java -I$O3/core/client -I$O3/core ovpncli.i
|
||||||
|
|
||||||
|
echo JAVA
|
||||||
|
javac *.java
|
||||||
|
|
||||||
|
echo CORE
|
||||||
|
g++ \
|
||||||
|
$CXX_COMPILER_FLAGS \
|
||||||
|
$PLATFORM_FLAGS \
|
||||||
|
$LIB_OPT_LEVEL $LIB_FPIC \
|
||||||
|
-Wall -Wno-sign-compare -Wno-unused-parameter \
|
||||||
|
-Wno-unused-local-typedefs \
|
||||||
|
$vis1 \
|
||||||
|
$ssl_def \
|
||||||
|
-DUSE_ASIO \
|
||||||
|
-DASIO_STANDALONE \
|
||||||
|
-DASIO_NO_DEPRECATED \
|
||||||
|
-DHAVE_LZ4 \
|
||||||
|
-I$O3/core/client \
|
||||||
|
-I$O3/core \
|
||||||
|
-I$DEP_DIR/asio/asio/include \
|
||||||
|
$ssl_inc \
|
||||||
|
-I$DEP_DIR/lz4/lz4-$PLATFORM/include \
|
||||||
|
-c $O3/core/client/ovpncli.cpp
|
||||||
|
|
||||||
|
echo WRAP
|
||||||
|
g++ \
|
||||||
|
$CXX_COMPILER_FLAGS \
|
||||||
|
$PLATFORM_FLAGS \
|
||||||
|
$opt2 $LIB_FPIC \
|
||||||
|
-fno-strict-aliasing \
|
||||||
|
-Wall \
|
||||||
|
$vis1 $vis2 \
|
||||||
|
-I$O3/core/client \
|
||||||
|
-I$O3/core \
|
||||||
|
$JINC \
|
||||||
|
$ssl_libdir \
|
||||||
|
-L$DEP_DIR/lz4/lz4-$PLATFORM/lib \
|
||||||
|
ovpncli_wrap.cxx \
|
||||||
|
ovpncli.o \
|
||||||
|
-o libovpncli.so \
|
||||||
|
-shared -Wl,-soname,libovpncli.so \
|
||||||
|
$ssl_lib \
|
||||||
|
-llz4
|
||||||
|
|
||||||
|
if [ "$DEBUG_BUILD" != "1" ]; then
|
||||||
|
echo STRIP $ABI
|
||||||
|
strip libovpncli.so
|
||||||
|
fi
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
// SWIG interface file for OpenVPN client
|
||||||
|
|
||||||
|
// enable director feature for OpenVPNClientBase virtual method callbacks
|
||||||
|
%module(directors="1") ovpncli
|
||||||
|
%feature("director") OpenVPNClient;
|
||||||
|
|
||||||
|
%include "std_string.i" // for std::string typemaps
|
||||||
|
%include "std_vector.i"
|
||||||
|
|
||||||
|
// top-level C++ implementation file
|
||||||
|
%{
|
||||||
|
#include "ovpncli.hpp"
|
||||||
|
%}
|
||||||
|
|
||||||
|
// ignore ClientAPI::OpenVPNClient bases other than TunBuilderBase
|
||||||
|
%ignore openvpn::ClientAPI::LogReceiver;
|
||||||
|
|
||||||
|
// modify exported C++ class names to incorporate their enclosing namespace
|
||||||
|
%rename(ClientAPI_OpenVPNClient) OpenVPNClient;
|
||||||
|
%rename(ClientAPI_TunBuilderBase) TunBuilderBase;
|
||||||
|
%rename(ClientAPI_ExternalPKIBase) ExternalPKIBase;
|
||||||
|
%rename(ClientAPI_ServerEntry) ServerEntry;
|
||||||
|
%rename(ClientAPI_EvalConfig) EvalConfig;
|
||||||
|
%rename(ClientAPI_ProvideCreds) ProvideCreds;
|
||||||
|
%rename(ClientAPI_SessionToken) SessionToken;
|
||||||
|
%rename(ClientAPI_DynamicChallenge) DynamicChallenge;
|
||||||
|
%rename(ClientAPI_KeyValue) KeyValue;
|
||||||
|
%rename(ClientAPI_Config) Config;
|
||||||
|
%rename(ClientAPI_Event) Event;
|
||||||
|
%rename(ClientAPI_ConnectionInfo) ConnectionInfo;
|
||||||
|
%rename(ClientAPI_Status) Status;
|
||||||
|
%rename(ClientAPI_LogInfo) LogInfo;
|
||||||
|
%rename(ClientAPI_InterfaceStats) InterfaceStats;
|
||||||
|
%rename(ClientAPI_TransportStats) TransportStats;
|
||||||
|
%rename(ClientAPI_MergeConfig) MergeConfig;
|
||||||
|
%rename(ClientAPI_ExternalPKIRequestBase) ExternalPKIRequestBase;
|
||||||
|
%rename(ClientAPI_ExternalPKICertRequest) ExternalPKICertRequest;
|
||||||
|
%rename(ClientAPI_ExternalPKISignRequest) ExternalPKISignRequest;
|
||||||
|
%rename(ClientAPI_RemoteOverride) RemoteOverride;
|
||||||
|
|
||||||
|
// declare vectors
|
||||||
|
namespace std {
|
||||||
|
%template(ClientAPI_ServerEntryVector) vector<openvpn::ClientAPI::ServerEntry>;
|
||||||
|
%template(ClientAPI_LLVector) vector<long long>;
|
||||||
|
};
|
||||||
|
|
||||||
|
// interface to be bridged between C++ and target language
|
||||||
|
%include "openvpn/pki/epkibase.hpp"
|
||||||
|
%include "openvpn/tun/builder/base.hpp"
|
||||||
|
%include "ovpncli.hpp"
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_ADDR_ADDRLIST_H
|
||||||
|
#define OPENVPN_ADDR_ADDRLIST_H
|
||||||
|
|
||||||
|
#include <openvpn/common/rc.hpp>
|
||||||
|
#include <openvpn/addr/ip.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
namespace IP {
|
||||||
|
|
||||||
|
// A list of unique IP addresses
|
||||||
|
class AddrList : public std::vector<IP::Addr>, public RC<thread_unsafe_refcount>
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef RCPtr<AddrList> Ptr;
|
||||||
|
|
||||||
|
void add(const IP::Addr& a)
|
||||||
|
{
|
||||||
|
if (!exists(a))
|
||||||
|
push_back(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool exists(const IP::Addr& a) const
|
||||||
|
{
|
||||||
|
for (const_iterator i = begin(); i != end(); ++i)
|
||||||
|
{
|
||||||
|
if (a == *i)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void dump() const
|
||||||
|
{
|
||||||
|
OPENVPN_LOG("******* AddrList::dump");
|
||||||
|
for (const_iterator i = begin(); i != end(); ++i)
|
||||||
|
OPENVPN_LOG(i->to_string());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,218 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_ADDR_ADDRPAIR_H
|
||||||
|
#define OPENVPN_ADDR_ADDRPAIR_H
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <openvpn/common/exception.hpp>
|
||||||
|
#include <openvpn/common/number.hpp>
|
||||||
|
#include <openvpn/common/split.hpp>
|
||||||
|
#include <openvpn/addr/ip.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
namespace IP {
|
||||||
|
|
||||||
|
// AddrMaskPair is basically an object that combines an IP address (v4 or v6)
|
||||||
|
// with a netmask or prefix length.
|
||||||
|
struct AddrMaskPair
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OPENVPN_EXCEPTION(addr_pair_mask_parse_error);
|
||||||
|
|
||||||
|
class StringPair {
|
||||||
|
public:
|
||||||
|
OPENVPN_SIMPLE_EXCEPTION(addr_pair_string_error);
|
||||||
|
|
||||||
|
StringPair()
|
||||||
|
: size_(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit StringPair(const std::string& s1)
|
||||||
|
: size_(1)
|
||||||
|
{
|
||||||
|
data[0] = s1;
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit StringPair(const std::string& s1, const std::string& s2)
|
||||||
|
: size_(2)
|
||||||
|
{
|
||||||
|
data[0] = s1;
|
||||||
|
data[1] = s2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void push_back(const std::string& s)
|
||||||
|
{
|
||||||
|
if (size_ < 2)
|
||||||
|
data[size_++] = s;
|
||||||
|
else
|
||||||
|
throw addr_pair_string_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string& operator[](const size_t i) const
|
||||||
|
{
|
||||||
|
if (i >= 2)
|
||||||
|
throw addr_pair_string_error();
|
||||||
|
return data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string& operator[](const size_t i)
|
||||||
|
{
|
||||||
|
if (i >= 2)
|
||||||
|
throw addr_pair_string_error();
|
||||||
|
return data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const { return size_; }
|
||||||
|
|
||||||
|
std::string render() const
|
||||||
|
{
|
||||||
|
switch (size_)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
return data[0];
|
||||||
|
case 2:
|
||||||
|
return data[0] + "/" + data[1];
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string data[2];
|
||||||
|
unsigned int size_;
|
||||||
|
};
|
||||||
|
|
||||||
|
static AddrMaskPair from_string(const std::string& s1, const std::string& s2, const char *title = nullptr)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (s2.empty())
|
||||||
|
{
|
||||||
|
const StringPair pair = Split::by_char<StringPair, NullLex, Split::NullLimit>(s1, '/');
|
||||||
|
return from_string_impl(pair, title);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const StringPair pair(s1, s2);
|
||||||
|
return from_string_impl(pair, title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
const StringPair pair(s1, s2);
|
||||||
|
error(e, pair.render(), title);
|
||||||
|
}
|
||||||
|
return AddrMaskPair(); // NOTREACHED
|
||||||
|
}
|
||||||
|
|
||||||
|
static AddrMaskPair from_string(const std::string& s, const char *title = nullptr)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
const StringPair pair = Split::by_char<StringPair, NullLex, Split::NullLimit>(s, '/');
|
||||||
|
return from_string_impl(pair, title);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
error(e, s, title);
|
||||||
|
}
|
||||||
|
return AddrMaskPair(); // NOTREACHED
|
||||||
|
}
|
||||||
|
|
||||||
|
static AddrMaskPair from_string(const StringPair& pair, const char *title = nullptr)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return from_string_impl(pair, title);
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
error(e, pair.render(), title);
|
||||||
|
}
|
||||||
|
return AddrMaskPair(); // NOTREACHED
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string(const bool netmask_form=false) const
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
if (netmask_form)
|
||||||
|
os << addr.to_string() << '/' << netmask.to_string();
|
||||||
|
else
|
||||||
|
os << addr.to_string() << '/' << netmask.prefix_len();
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_canonical() const
|
||||||
|
{
|
||||||
|
return (addr & netmask) == addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr::Version version() const
|
||||||
|
{
|
||||||
|
const Addr::Version v1 = addr.version();
|
||||||
|
const Addr::Version v2 = netmask.version();
|
||||||
|
if (v1 == v2)
|
||||||
|
return v1;
|
||||||
|
else
|
||||||
|
return Addr::UNSPEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr addr;
|
||||||
|
Addr netmask;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void error(const std::exception& e, const std::string& s, const char *title)
|
||||||
|
{
|
||||||
|
if (!title)
|
||||||
|
title = "";
|
||||||
|
OPENVPN_THROW(addr_pair_mask_parse_error, "AddrMaskPair parse error '" << title << "': " << s << " : " << e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
static AddrMaskPair from_string_impl(const StringPair& pair, const char *title = nullptr)
|
||||||
|
{
|
||||||
|
AddrMaskPair ret;
|
||||||
|
if (pair.size() == 1 || pair.size() == 2)
|
||||||
|
{
|
||||||
|
ret.addr = Addr::from_string(pair[0], title);
|
||||||
|
if (pair.size() == 2 && !pair[1].empty())
|
||||||
|
{
|
||||||
|
if (is_number(pair[1].c_str()))
|
||||||
|
ret.netmask = Addr::netmask_from_prefix_len(ret.addr.version(),
|
||||||
|
parse_number_throw<unsigned int>(pair[1], "prefix length"));
|
||||||
|
else
|
||||||
|
ret.netmask = Addr::from_string(pair[1]);
|
||||||
|
ret.netmask.prefix_len(); // verify that netmask is ok
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ret.netmask = Addr::from_zero_complement(ret.addr.version());
|
||||||
|
ret.addr.verify_version_consistency(ret.netmask);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw addr_pair_mask_parse_error("only one or two address terms allowed");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
OPENVPN_OSTREAM(AddrMaskPair, to_string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,956 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_ADDR_IP_H
|
||||||
|
#define OPENVPN_ADDR_IP_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstring> // for std::memset
|
||||||
|
|
||||||
|
#include <openvpn/io/io.hpp>
|
||||||
|
|
||||||
|
#include <openvpn/common/size.hpp>
|
||||||
|
#include <openvpn/common/exception.hpp>
|
||||||
|
#include <openvpn/common/ostream.hpp>
|
||||||
|
#include <openvpn/common/hash.hpp>
|
||||||
|
#include <openvpn/addr/ipv4.hpp>
|
||||||
|
#include <openvpn/addr/ipv6.hpp>
|
||||||
|
#include <openvpn/addr/iperr.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
// This is our fundamental IP address class that handles IPv4 or IPv6
|
||||||
|
// IP addresses. It is implemented as a discriminated union of IPv4::Addr
|
||||||
|
// and IPv6::Addr.
|
||||||
|
namespace IP {
|
||||||
|
|
||||||
|
OPENVPN_EXCEPTION(ip_exception);
|
||||||
|
|
||||||
|
class Addr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Version { UNSPEC, V4, V6 };
|
||||||
|
|
||||||
|
enum { V4_MASK=(1<<0), V6_MASK=(1<<1) };
|
||||||
|
typedef unsigned int VersionMask;
|
||||||
|
|
||||||
|
enum VersionSize {
|
||||||
|
V4_SIZE = IPv4::Addr::SIZE,
|
||||||
|
V6_SIZE = IPv6::Addr::SIZE,
|
||||||
|
};
|
||||||
|
|
||||||
|
Addr(const Addr& other, const char *title = nullptr, Version required_version = UNSPEC)
|
||||||
|
: ver(other.ver)
|
||||||
|
{
|
||||||
|
other.validate_version(title, required_version);
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case V4:
|
||||||
|
u.v4 = other.u.v4;
|
||||||
|
break;
|
||||||
|
case V6:
|
||||||
|
u.v6 = other.u.v6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr(const std::string& ipstr, const char *title = nullptr, Version required_version = UNSPEC)
|
||||||
|
: Addr(from_string(ipstr, title, required_version))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr(const std::string& ipstr, const std::string& title, Version required_version = UNSPEC)
|
||||||
|
: Addr(from_string(ipstr, title.c_str(), required_version))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void validate_version(const char *title, Version required_version) const
|
||||||
|
{
|
||||||
|
if (required_version != UNSPEC && required_version != ver)
|
||||||
|
throw ip_exception(internal::format_error(to_string(), title, version_string_static(required_version), "wrong IP version"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void validate_version(const std::string& title, Version required_version) const
|
||||||
|
{
|
||||||
|
validate_version(title.c_str(), required_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string validate(const std::string& ipstr, const char *title = nullptr, Version required_version = UNSPEC)
|
||||||
|
{
|
||||||
|
Addr a = from_string(ipstr, title, required_version);
|
||||||
|
return a.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string validate(const std::string& ipstr, const std::string& title, Version required_version = UNSPEC)
|
||||||
|
{
|
||||||
|
return validate(ipstr, title.c_str(), required_version);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_valid(const std::string& ipstr)
|
||||||
|
{
|
||||||
|
// fast path -- rule out validity if invalid chars
|
||||||
|
for (size_t i = 0; i < ipstr.length(); ++i)
|
||||||
|
{
|
||||||
|
const char c = ipstr[i];
|
||||||
|
if (!((c >= '0' && c <= '9')
|
||||||
|
|| (c >= 'a' && c <= 'f')
|
||||||
|
|| (c >= 'A' && c <= 'F')
|
||||||
|
|| (c == '.' || c == ':' || c == '%')))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// slow path
|
||||||
|
{
|
||||||
|
openvpn_io::error_code ec;
|
||||||
|
openvpn_io::ip::make_address(ipstr, ec);
|
||||||
|
return !ec;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_string(const std::string& ipstr, const char *title = nullptr, Version required_version = UNSPEC)
|
||||||
|
{
|
||||||
|
openvpn_io::error_code ec;
|
||||||
|
openvpn_io::ip::address a = openvpn_io::ip::make_address(ipstr, ec);
|
||||||
|
if (ec)
|
||||||
|
throw ip_exception(internal::format_error(ipstr, title, "", ec));
|
||||||
|
const Addr ret = from_asio(a);
|
||||||
|
if (required_version != UNSPEC && required_version != ret.ver)
|
||||||
|
throw ip_exception(internal::format_error(ipstr, title, version_string_static(required_version), "wrong IP version"));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_hex(Version v, const std::string& s)
|
||||||
|
{
|
||||||
|
if (v == V4)
|
||||||
|
return from_ipv4(IPv4::Addr::from_hex(s));
|
||||||
|
else if (v == V6)
|
||||||
|
return from_ipv6(IPv6::Addr::from_hex(s));
|
||||||
|
else
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_ipv4(const IPv4::Addr& addr)
|
||||||
|
{
|
||||||
|
Addr a;
|
||||||
|
a.ver = V4;
|
||||||
|
a.u.v4 = addr;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_ipv6(const IPv6::Addr& addr)
|
||||||
|
{
|
||||||
|
Addr a;
|
||||||
|
a.ver = V6;
|
||||||
|
a.u.v6 = addr;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
const IPv4::Addr& to_ipv4() const
|
||||||
|
{
|
||||||
|
if (ver == V4)
|
||||||
|
return u.v4;
|
||||||
|
else
|
||||||
|
throw ip_exception("address is not IPv4");
|
||||||
|
}
|
||||||
|
|
||||||
|
const IPv6::Addr& to_ipv6() const
|
||||||
|
{
|
||||||
|
if (ver == V6)
|
||||||
|
return u.v6;
|
||||||
|
else
|
||||||
|
throw ip_exception("address is not IPv6");
|
||||||
|
}
|
||||||
|
|
||||||
|
const IPv4::Addr& to_ipv4_nocheck() const
|
||||||
|
{
|
||||||
|
return u.v4;
|
||||||
|
}
|
||||||
|
|
||||||
|
const IPv6::Addr& to_ipv6_nocheck() const
|
||||||
|
{
|
||||||
|
return u.v6;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_sockaddr(const struct sockaddr *sa)
|
||||||
|
{
|
||||||
|
if (sa->sa_family == AF_INET)
|
||||||
|
return from_ipv4(IPv4::Addr::from_sockaddr((struct sockaddr_in *)sa));
|
||||||
|
else if (sa->sa_family == AF_INET6)
|
||||||
|
return from_ipv6(IPv6::Addr::from_sockaddr((struct sockaddr_in6 *)sa));
|
||||||
|
else
|
||||||
|
return Addr();
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool sockaddr_defined(const struct sockaddr *sa)
|
||||||
|
{
|
||||||
|
return sa && (sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_ulong(Version v, unsigned long ul)
|
||||||
|
{
|
||||||
|
if (v == V4)
|
||||||
|
return from_ipv4(IPv4::Addr::from_ulong(ul));
|
||||||
|
else if (v == V6)
|
||||||
|
return from_ipv6(IPv6::Addr::from_ulong(ul));
|
||||||
|
else
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
|
||||||
|
// return *this as a ulong, will raise exception on overflow
|
||||||
|
unsigned long to_ulong() const
|
||||||
|
{
|
||||||
|
if (ver == V4)
|
||||||
|
return u.v4.to_ulong();
|
||||||
|
else if (ver == V6)
|
||||||
|
return u.v6.to_ulong();
|
||||||
|
else
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_long(Version v, long ul)
|
||||||
|
{
|
||||||
|
if (v == V4)
|
||||||
|
return from_ipv4(IPv4::Addr::from_long(ul));
|
||||||
|
else if (v == V6)
|
||||||
|
return from_ipv6(IPv6::Addr::from_long(ul));
|
||||||
|
else
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
|
||||||
|
// return *this as a long, will raise exception on overflow
|
||||||
|
long to_long() const
|
||||||
|
{
|
||||||
|
if (ver == V4)
|
||||||
|
return u.v4.to_long();
|
||||||
|
else if (ver == V6)
|
||||||
|
return u.v6.to_long();
|
||||||
|
else
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
|
||||||
|
// return Addr from 16 byte binary string
|
||||||
|
static Addr from_byte_string(const unsigned char *bytestr)
|
||||||
|
{
|
||||||
|
Addr a;
|
||||||
|
if (IPv6::Addr::byte_string_is_v4(bytestr))
|
||||||
|
{
|
||||||
|
a.ver = V4;
|
||||||
|
a.u.v4 = IPv4::Addr::from_uint32_net(IPv6::Addr::v4_from_byte_string(bytestr));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a.ver = V4;
|
||||||
|
a.u.v6 = IPv6::Addr::from_byte_string(bytestr);
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert Addr to 16 byte binary string
|
||||||
|
void to_byte_string(unsigned char *bytestr) const
|
||||||
|
{
|
||||||
|
if (ver == V4)
|
||||||
|
IPv6::Addr::v4_to_byte_string(bytestr, u.v4.to_uint32_net());
|
||||||
|
else if (ver == V6)
|
||||||
|
u.v6.to_byte_string(bytestr);
|
||||||
|
else
|
||||||
|
std::memset(bytestr, 0, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert Addr to variable length byte string
|
||||||
|
void to_byte_string_variable(unsigned char *bytestr) const
|
||||||
|
{
|
||||||
|
if (ver == V4)
|
||||||
|
u.v4.to_byte_string(bytestr);
|
||||||
|
else if (ver == V6)
|
||||||
|
u.v6.to_byte_string(bytestr);
|
||||||
|
else
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t to_uint32_net() const // return value in net byte order
|
||||||
|
{
|
||||||
|
if (ver == V4)
|
||||||
|
return u.v4.to_uint32_net();
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// construct an address where all bits are zero
|
||||||
|
static Addr from_zero(Version v)
|
||||||
|
{
|
||||||
|
if (v == V4)
|
||||||
|
return from_ipv4(IPv4::Addr::from_zero());
|
||||||
|
else if (v == V6)
|
||||||
|
return from_ipv6(IPv6::Addr::from_zero());
|
||||||
|
else
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
|
||||||
|
// construct an address where all bits are zero
|
||||||
|
static Addr from_one(Version v)
|
||||||
|
{
|
||||||
|
if (v == V4)
|
||||||
|
return from_ipv4(IPv4::Addr::from_one());
|
||||||
|
else if (v == V6)
|
||||||
|
return from_ipv6(IPv6::Addr::from_one());
|
||||||
|
else
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
|
||||||
|
// construct an address where all bits are one
|
||||||
|
static Addr from_zero_complement(Version v)
|
||||||
|
{
|
||||||
|
if (v == V4)
|
||||||
|
return from_ipv4(IPv4::Addr::from_zero_complement());
|
||||||
|
else if (v == V6)
|
||||||
|
return from_ipv6(IPv6::Addr::from_zero_complement());
|
||||||
|
else
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
|
||||||
|
// build a netmask using given prefix_len
|
||||||
|
static Addr netmask_from_prefix_len(Version v, const unsigned int prefix_len)
|
||||||
|
{
|
||||||
|
if (v == V4)
|
||||||
|
return from_ipv4(IPv4::Addr::netmask_from_prefix_len(prefix_len));
|
||||||
|
else if (v == V6)
|
||||||
|
return from_ipv6(IPv6::Addr::netmask_from_prefix_len(prefix_len));
|
||||||
|
else
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
|
||||||
|
// build a netmask using *this as extent
|
||||||
|
Addr netmask_from_extent() const
|
||||||
|
{
|
||||||
|
if (ver == V4)
|
||||||
|
return from_ipv4(u.v4.netmask_from_extent());
|
||||||
|
else if (ver == V6)
|
||||||
|
return from_ipv6(u.v6.netmask_from_extent());
|
||||||
|
else
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string() const
|
||||||
|
{
|
||||||
|
if (ver != UNSPEC)
|
||||||
|
{
|
||||||
|
const openvpn_io::ip::address a = to_asio();
|
||||||
|
std::string ret = a.to_string();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return "UNSPEC";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string_bracket_ipv6() const
|
||||||
|
{
|
||||||
|
std::string ret;
|
||||||
|
if (ver == V6)
|
||||||
|
ret += '[';
|
||||||
|
ret += to_string();
|
||||||
|
if (ver == V6)
|
||||||
|
ret += ']';
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_hex() const
|
||||||
|
{
|
||||||
|
if (ver == V4)
|
||||||
|
return u.v4.to_hex();
|
||||||
|
else if (ver == V6)
|
||||||
|
return u.v6.to_hex();
|
||||||
|
else
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string arpa() const
|
||||||
|
{
|
||||||
|
if (ver == V4)
|
||||||
|
return u.v4.arpa();
|
||||||
|
else if (ver == V6)
|
||||||
|
return u.v6.arpa();
|
||||||
|
else
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_asio(const openvpn_io::ip::address& addr)
|
||||||
|
{
|
||||||
|
if (addr.is_v4())
|
||||||
|
{
|
||||||
|
Addr a;
|
||||||
|
a.ver = V4;
|
||||||
|
a.u.v4 = IPv4::Addr::from_asio(addr.to_v4());
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
else if (addr.is_v6())
|
||||||
|
{
|
||||||
|
Addr a;
|
||||||
|
a.ver = V6;
|
||||||
|
a.u.v6 = IPv6::Addr::from_asio(addr.to_v6());
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
|
||||||
|
openvpn_io::ip::address to_asio() const
|
||||||
|
{
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case V4:
|
||||||
|
return openvpn_io::ip::address_v4(u.v4.to_asio());
|
||||||
|
case V6:
|
||||||
|
return openvpn_io::ip::address_v6(u.v6.to_asio());
|
||||||
|
default:
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator+(const long delta) const {
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case V4:
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.ver = V4;
|
||||||
|
ret.u.v4 = u.v4 + delta;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case V6:
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.ver = V6;
|
||||||
|
ret.u.v6 = u.v6 + delta;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator-(const long delta) const {
|
||||||
|
return operator+(-delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OPENVPN_IP_OPERATOR_BINOP(OP) \
|
||||||
|
Addr operator OP (const Addr& other) const { \
|
||||||
|
if (ver != other.ver) \
|
||||||
|
throw ip_exception("version inconsistency"); \
|
||||||
|
switch (ver) \
|
||||||
|
{ \
|
||||||
|
case V4: \
|
||||||
|
{ \
|
||||||
|
Addr ret; \
|
||||||
|
ret.ver = V4; \
|
||||||
|
ret.u.v4 = u.v4 OP other.u.v4; \
|
||||||
|
return ret; \
|
||||||
|
} \
|
||||||
|
case V6: \
|
||||||
|
{ \
|
||||||
|
Addr ret; \
|
||||||
|
ret.ver = V6; \
|
||||||
|
ret.u.v6 = u.v6 OP other.u.v6; \
|
||||||
|
return ret; \
|
||||||
|
} \
|
||||||
|
default: \
|
||||||
|
throw ip_exception("address unspecified"); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
OPENVPN_IP_OPERATOR_BINOP(+)
|
||||||
|
OPENVPN_IP_OPERATOR_BINOP(-)
|
||||||
|
OPENVPN_IP_OPERATOR_BINOP(*)
|
||||||
|
OPENVPN_IP_OPERATOR_BINOP(/)
|
||||||
|
OPENVPN_IP_OPERATOR_BINOP(%)
|
||||||
|
OPENVPN_IP_OPERATOR_BINOP(&)
|
||||||
|
OPENVPN_IP_OPERATOR_BINOP(|)
|
||||||
|
|
||||||
|
#undef OPENVPN_IP_OPERATOR_BINOP
|
||||||
|
|
||||||
|
Addr operator<<(const unsigned int shift) const {
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case V4:
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.ver = V4;
|
||||||
|
ret.u.v4 = u.v4 << shift;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case V6:
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.ver = V6;
|
||||||
|
ret.u.v6 = u.v6 << shift;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator>>(const unsigned int shift) const {
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case V4:
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.ver = V4;
|
||||||
|
ret.u.v4 = u.v4 >> shift;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case V6:
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.ver = V6;
|
||||||
|
ret.u.v6 = u.v6 >> shift;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator~() const {
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case V4:
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.ver = V4;
|
||||||
|
ret.u.v4 = ~u.v4;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case V6:
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.ver = V6;
|
||||||
|
ret.u.v6 = ~u.v6;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr network_addr(const unsigned int prefix_len) const {
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case V4:
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.ver = V4;
|
||||||
|
ret.u.v4 = u.v4.network_addr(prefix_len);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
case V6:
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.ver = V6;
|
||||||
|
ret.u.v6 = u.v6.network_addr(prefix_len);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Addr& other) const
|
||||||
|
{
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case UNSPEC:
|
||||||
|
return other.ver == UNSPEC;
|
||||||
|
case V4:
|
||||||
|
if (ver == other.ver)
|
||||||
|
return u.v4 == other.u.v4;
|
||||||
|
break;
|
||||||
|
case V6:
|
||||||
|
if (ver == other.ver)
|
||||||
|
return u.v6 == other.u.v6;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const Addr& other) const
|
||||||
|
{
|
||||||
|
return !operator==(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OPENVPN_IP_OPERATOR_REL(OP) \
|
||||||
|
bool operator OP(const Addr& other) const \
|
||||||
|
{ \
|
||||||
|
if (ver == other.ver) \
|
||||||
|
{ \
|
||||||
|
switch (ver) \
|
||||||
|
{ \
|
||||||
|
case V4: \
|
||||||
|
return u.v4 OP other.u.v4; \
|
||||||
|
case V6: \
|
||||||
|
return u.v6 OP other.u.v6; \
|
||||||
|
default: \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
else if (ver OP other.ver) \
|
||||||
|
return true; \
|
||||||
|
else \
|
||||||
|
return false; \
|
||||||
|
}
|
||||||
|
|
||||||
|
OPENVPN_IP_OPERATOR_REL(<)
|
||||||
|
OPENVPN_IP_OPERATOR_REL(>)
|
||||||
|
OPENVPN_IP_OPERATOR_REL(<=)
|
||||||
|
OPENVPN_IP_OPERATOR_REL(>=)
|
||||||
|
|
||||||
|
#undef OPENVPN_IP_OPERATOR_REL
|
||||||
|
|
||||||
|
bool unspecified() const
|
||||||
|
{
|
||||||
|
return all_zeros();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool specified() const
|
||||||
|
{
|
||||||
|
return !unspecified();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool all_zeros() const
|
||||||
|
{
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case V4:
|
||||||
|
return u.v4.all_zeros();
|
||||||
|
case V6:
|
||||||
|
return u.v6.all_zeros();
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool all_ones() const
|
||||||
|
{
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case V4:
|
||||||
|
return u.v4.all_ones();
|
||||||
|
case V6:
|
||||||
|
return u.v6.all_ones();
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_loopback() const
|
||||||
|
{
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case V4:
|
||||||
|
return u.v4.is_loopback();
|
||||||
|
case V6:
|
||||||
|
return u.v6.is_loopback();
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool defined() const
|
||||||
|
{
|
||||||
|
return ver != UNSPEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *version_string() const
|
||||||
|
{
|
||||||
|
return version_string_static(ver);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *version_string_static(Version ver)
|
||||||
|
{
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case V4:
|
||||||
|
return "v4";
|
||||||
|
case V6:
|
||||||
|
return "v6";
|
||||||
|
default:
|
||||||
|
return "v?";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Version version() const { return ver; }
|
||||||
|
|
||||||
|
static VersionMask version_mask(const Version ver)
|
||||||
|
{
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case V4:
|
||||||
|
return V4_MASK;
|
||||||
|
case V6:
|
||||||
|
return V6_MASK;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VersionMask version_mask() const
|
||||||
|
{
|
||||||
|
return version_mask(ver);
|
||||||
|
}
|
||||||
|
|
||||||
|
int version_index() const
|
||||||
|
{
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case V4:
|
||||||
|
return 0;
|
||||||
|
case V6:
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
throw ip_exception("version index undefined");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int family() const
|
||||||
|
{
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case V4:
|
||||||
|
return AF_INET;
|
||||||
|
case V6:
|
||||||
|
return AF_INET6;
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_compatible(const Addr& other) const
|
||||||
|
{
|
||||||
|
return ver == other.ver;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_ipv6() const
|
||||||
|
{
|
||||||
|
return ver == V6;
|
||||||
|
}
|
||||||
|
|
||||||
|
void verify_version_consistency(const Addr& other) const
|
||||||
|
{
|
||||||
|
if (!is_compatible(other))
|
||||||
|
throw ip_exception("version inconsistency");
|
||||||
|
}
|
||||||
|
|
||||||
|
// throw exception if address is not a valid netmask
|
||||||
|
void validate_netmask()
|
||||||
|
{
|
||||||
|
prefix_len();
|
||||||
|
}
|
||||||
|
|
||||||
|
// number of network bits in netmask,
|
||||||
|
// throws exception if addr is not a netmask
|
||||||
|
unsigned int prefix_len() const
|
||||||
|
{
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case V4:
|
||||||
|
return u.v4.prefix_len();
|
||||||
|
case V6:
|
||||||
|
return u.v6.prefix_len();
|
||||||
|
default:
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IPv6 scope ID or -1 if not IPv6
|
||||||
|
int scope_id() const
|
||||||
|
{
|
||||||
|
return ver == V6 ? u.v6.scope_id() : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// number of host bits in netmask
|
||||||
|
unsigned int host_len() const
|
||||||
|
{
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case V4:
|
||||||
|
return u.v4.host_len();
|
||||||
|
case V6:
|
||||||
|
return u.v6.host_len();
|
||||||
|
default:
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the number of host addresses contained within netmask
|
||||||
|
Addr extent_from_netmask() const
|
||||||
|
{
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case V4:
|
||||||
|
return from_ipv4(u.v4.extent_from_netmask());
|
||||||
|
case V6:
|
||||||
|
return from_ipv6(u.v6.extent_from_netmask());
|
||||||
|
default:
|
||||||
|
throw ip_exception("address unspecified");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// address size in bits
|
||||||
|
unsigned int size() const
|
||||||
|
{
|
||||||
|
return version_size(ver);
|
||||||
|
}
|
||||||
|
|
||||||
|
// address size in bytes
|
||||||
|
unsigned int size_bytes() const
|
||||||
|
{
|
||||||
|
return size() / 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
// address size in bits of particular IP version
|
||||||
|
static unsigned int version_size(Version v)
|
||||||
|
{
|
||||||
|
if (v == V4)
|
||||||
|
return IPv4::Addr::SIZE;
|
||||||
|
else if (v == V6)
|
||||||
|
return IPv6::Addr::SIZE;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t hashval() const
|
||||||
|
{
|
||||||
|
std::size_t seed = 0;
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case Addr::V4:
|
||||||
|
Hash::combine(seed, 4, u.v4);
|
||||||
|
break;
|
||||||
|
case Addr::V6:
|
||||||
|
Hash::combine(seed, 6, u.v6);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return seed;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef OPENVPN_IP_IMMUTABLE
|
||||||
|
private:
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Addr()
|
||||||
|
: ver(UNSPEC)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
ver = UNSPEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr& operator=(const Addr& other)
|
||||||
|
{
|
||||||
|
switch (ver = other.ver)
|
||||||
|
{
|
||||||
|
case V4:
|
||||||
|
u.v4 = other.u.v4;
|
||||||
|
break;
|
||||||
|
case V6:
|
||||||
|
u.v6 = other.u.v6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr& operator++()
|
||||||
|
{
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case V4:
|
||||||
|
++u.v4;
|
||||||
|
break;
|
||||||
|
case V6:
|
||||||
|
++u.v6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr& operator+=(const long delta)
|
||||||
|
{
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case V4:
|
||||||
|
u.v4 += delta;
|
||||||
|
break;
|
||||||
|
case V6:
|
||||||
|
u.v6 += delta;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr& operator-=(const long delta)
|
||||||
|
{
|
||||||
|
switch (ver)
|
||||||
|
{
|
||||||
|
case V4:
|
||||||
|
u.v4 -= delta;
|
||||||
|
break;
|
||||||
|
case V6:
|
||||||
|
u.v6 -= delta;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_ipv4_from_uint32(const IPv4::Addr::base_type addr)
|
||||||
|
{
|
||||||
|
ver = V4;
|
||||||
|
u.v4 = IPv4::Addr::from_uint32(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
union {
|
||||||
|
IPv4::Addr v4;
|
||||||
|
IPv6::Addr v6;
|
||||||
|
} u;
|
||||||
|
|
||||||
|
Version ver;
|
||||||
|
};
|
||||||
|
|
||||||
|
OPENVPN_OSTREAM(Addr, to_string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OPENVPN_HASH_METHOD(openvpn::IP::Addr, hashval);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_ADDR_IPERR_H
|
||||||
|
#define OPENVPN_ADDR_IPERR_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <openvpn/io/io.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
namespace IP {
|
||||||
|
namespace internal {
|
||||||
|
// Called internally by IP, IPv4, and IPv6 classes
|
||||||
|
|
||||||
|
inline std::string format_error(const std::string& ipstr, const char *title, const char *ipver, const openvpn_io::error_code& ec)
|
||||||
|
{
|
||||||
|
std::string err = "error parsing";
|
||||||
|
if (title)
|
||||||
|
{
|
||||||
|
err += ' ';
|
||||||
|
err += title;
|
||||||
|
}
|
||||||
|
err += " IP";
|
||||||
|
err += ipver;
|
||||||
|
err += " address '";
|
||||||
|
err += ipstr;
|
||||||
|
err += "' : ";
|
||||||
|
err += ec.message();
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string format_error(const std::string& ipstr, const char *title, const char *ipver, const char *message)
|
||||||
|
{
|
||||||
|
std::string err = "error parsing";
|
||||||
|
if (title)
|
||||||
|
{
|
||||||
|
err += ' ';
|
||||||
|
err += title;
|
||||||
|
}
|
||||||
|
err += " IP";
|
||||||
|
err += ipver;
|
||||||
|
err += " address '";
|
||||||
|
err += ipstr;
|
||||||
|
err += '\'';
|
||||||
|
if (message)
|
||||||
|
{
|
||||||
|
err += " : ";
|
||||||
|
err += message;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,571 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_ADDR_IPV4_H
|
||||||
|
#define OPENVPN_ADDR_IPV4_H
|
||||||
|
|
||||||
|
#include <cstring> // for std::memcpy, std::memset
|
||||||
|
#include <sstream>
|
||||||
|
#include <cstdint> // for std::uint32_t
|
||||||
|
|
||||||
|
#include <openvpn/io/io.hpp>
|
||||||
|
|
||||||
|
#include <openvpn/common/size.hpp>
|
||||||
|
#include <openvpn/common/exception.hpp>
|
||||||
|
#include <openvpn/common/endian.hpp>
|
||||||
|
#include <openvpn/common/ostream.hpp>
|
||||||
|
#include <openvpn/common/socktypes.hpp>
|
||||||
|
#include <openvpn/common/ffs.hpp>
|
||||||
|
#include <openvpn/common/hexstr.hpp>
|
||||||
|
#include <openvpn/common/hash.hpp>
|
||||||
|
#include <openvpn/addr/iperr.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
namespace IP {
|
||||||
|
class Addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fundamental classes for representing an IPv4 IP address.
|
||||||
|
|
||||||
|
namespace IPv4 {
|
||||||
|
|
||||||
|
OPENVPN_EXCEPTION(ipv4_exception);
|
||||||
|
|
||||||
|
class Addr // NOTE: must be union-legal, so default constructor does not initialize
|
||||||
|
{
|
||||||
|
friend class IP::Addr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum { SIZE=32 };
|
||||||
|
|
||||||
|
typedef std::uint32_t base_type;
|
||||||
|
typedef std::int32_t signed_base_type;
|
||||||
|
|
||||||
|
static Addr from_addr(const Addr& addr)
|
||||||
|
{
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_in_addr(const struct in_addr *in4)
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = ntohl(in4->s_addr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct in_addr to_in_addr() const
|
||||||
|
{
|
||||||
|
struct in_addr ret;
|
||||||
|
ret.s_addr = htonl(u.addr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_sockaddr(const struct sockaddr_in *sa)
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = ntohl(sa->sin_addr.s_addr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in to_sockaddr() const
|
||||||
|
{
|
||||||
|
struct sockaddr_in ret;
|
||||||
|
std::memset(&ret, 0, sizeof(ret));
|
||||||
|
ret.sin_family = AF_INET;
|
||||||
|
ret.sin_port = 0;
|
||||||
|
ret.sin_addr.s_addr = htonl(u.addr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_uint32(const base_type addr) // host byte order
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = addr;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t to_uint32() const // host byte order
|
||||||
|
{
|
||||||
|
return u.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_uint32_net(const base_type addr) // addr in net byte order
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = ntohl(addr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void to_byte_string(unsigned char *bytestr) const
|
||||||
|
{
|
||||||
|
*(base_type*)bytestr = ntohl(u.addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t to_uint32_net() const // return value in net byte order
|
||||||
|
{
|
||||||
|
return htonl(u.addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_ulong(unsigned long ul)
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = (base_type)ul;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return *this as a unsigned long
|
||||||
|
unsigned long to_ulong() const
|
||||||
|
{
|
||||||
|
return (unsigned long)u.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_long(long ul)
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = (base_type)(signed_base_type)ul;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return *this as a long
|
||||||
|
long to_long() const
|
||||||
|
{
|
||||||
|
return (long)(signed_base_type)u.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_bytes(const unsigned char *bytes) // host byte order
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
std::memcpy(ret.u.bytes, bytes, 4);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_bytes_net(const unsigned char *bytes) // network byte order
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
std::memcpy(ret.u.bytes, bytes, 4);
|
||||||
|
ret.u.addr = ntohl(ret.u.addr);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_zero()
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.zero();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_one()
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.one();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_zero_complement()
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.zero_complement();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// build a netmask using given prefix_len
|
||||||
|
static Addr netmask_from_prefix_len(const unsigned int prefix_len)
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = prefix_len_to_netmask(prefix_len);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// build a netmask using given extent
|
||||||
|
Addr netmask_from_extent() const
|
||||||
|
{
|
||||||
|
const int lb = find_last_set(u.addr - 1);
|
||||||
|
return netmask_from_prefix_len(SIZE - lb);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_string(const std::string& ipstr, const char *title = nullptr)
|
||||||
|
{
|
||||||
|
openvpn_io::error_code ec;
|
||||||
|
openvpn_io::ip::address_v4 a = openvpn_io::ip::make_address_v4(ipstr, ec);
|
||||||
|
if (ec)
|
||||||
|
throw ipv4_exception(IP::internal::format_error(ipstr, title, "v4", ec));
|
||||||
|
return from_asio(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string() const
|
||||||
|
{
|
||||||
|
const openvpn_io::ip::address_v4 a = to_asio();
|
||||||
|
std::string ret = a.to_string();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_hex(const std::string& s)
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = 0;
|
||||||
|
size_t len = s.length();
|
||||||
|
size_t base = 0;
|
||||||
|
if (len > 0 && s[len-1] == 'L')
|
||||||
|
len -= 1;
|
||||||
|
if (len >= 2 && s[0] == '0' && s[1] == 'x')
|
||||||
|
{
|
||||||
|
base = 2;
|
||||||
|
len -= 2;
|
||||||
|
}
|
||||||
|
if (len < 1 || len > 8)
|
||||||
|
throw ipv4_exception("parse hex error");
|
||||||
|
size_t di = (len-1)>>1;
|
||||||
|
for (int i = (len & 1) ? -1 : 0; i < int(len); i += 2)
|
||||||
|
{
|
||||||
|
const size_t idx = base + i;
|
||||||
|
const int bh = (i >= 0) ? parse_hex_char(s[idx]) : 0;
|
||||||
|
const int bl = parse_hex_char(s[idx+1]);
|
||||||
|
if (bh == -1 || bl == -1)
|
||||||
|
throw ipv4_exception("parse hex error");
|
||||||
|
ret.u.bytes[Endian::e4(di--)] = (bh<<4) + bl;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_hex() const
|
||||||
|
{
|
||||||
|
std::string ret;
|
||||||
|
ret.reserve(8);
|
||||||
|
bool firstnonzero = false;
|
||||||
|
for (size_t i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
const unsigned char b = u.bytes[Endian::e4rev(i)];
|
||||||
|
if (b || firstnonzero || i == 3)
|
||||||
|
{
|
||||||
|
const char bh = b >> 4;
|
||||||
|
if (bh || firstnonzero)
|
||||||
|
ret += render_hex_char(bh);
|
||||||
|
ret += render_hex_char(b & 0x0F);
|
||||||
|
firstnonzero = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string arpa() const
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
os << int(u.bytes[Endian::e4(0)]) << '.'
|
||||||
|
<< int(u.bytes[Endian::e4(1)]) << '.'
|
||||||
|
<< int(u.bytes[Endian::e4(2)]) << '.'
|
||||||
|
<< int(u.bytes[Endian::e4(3)]) << ".in-addr.arpa";
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_asio(const openvpn_io::ip::address_v4& asio_addr)
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = (std::uint32_t)asio_addr.to_uint();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
openvpn_io::ip::address_v4 to_asio() const
|
||||||
|
{
|
||||||
|
return openvpn_io::ip::address_v4(u.addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator&(const Addr& other) const {
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = u.addr & other.u.addr;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator|(const Addr& other) const {
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = u.addr | other.u.addr;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator+(const long delta) const {
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = u.addr + (std::uint32_t)delta;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator+(const Addr& other) const {
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = u.addr + other.u.addr;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator-(const long delta) const {
|
||||||
|
return operator+(-delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator-(const Addr& other) const {
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = u.addr - other.u.addr;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator*(const Addr& other) const {
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = u.addr * other.u.addr;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator/(const Addr& other) const {
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = u.addr / other.u.addr;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator%(const Addr& other) const {
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = u.addr % other.u.addr;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator<<(const unsigned int shift) const {
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = u.addr << shift;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator>>(const unsigned int shift) const {
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = u.addr >> shift;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator~() const {
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = ~u.addr;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the network that contains the current address
|
||||||
|
Addr network_addr(const unsigned int prefix_len) const
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = u.addr & prefix_len_to_netmask(prefix_len);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Addr& other) const
|
||||||
|
{
|
||||||
|
return u.addr == other.u.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const Addr& other) const
|
||||||
|
{
|
||||||
|
return u.addr != other.u.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<(const Addr& other) const
|
||||||
|
{
|
||||||
|
return u.addr < other.u.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>(const Addr& other) const
|
||||||
|
{
|
||||||
|
return u.addr > other.u.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator<=(const Addr& other) const
|
||||||
|
{
|
||||||
|
return u.addr <= other.u.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator>=(const Addr& other) const
|
||||||
|
{
|
||||||
|
return u.addr >= other.u.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool unspecified() const
|
||||||
|
{
|
||||||
|
return all_zeros();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool specified() const
|
||||||
|
{
|
||||||
|
return !unspecified();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool all_zeros() const
|
||||||
|
{
|
||||||
|
return u.addr == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool all_ones() const
|
||||||
|
{
|
||||||
|
return ~u.addr == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_loopback() const
|
||||||
|
{
|
||||||
|
return (u.addr & 0x7F000000) == 0x7F000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// number of network bits in netmask,
|
||||||
|
// throws exception if addr is not a netmask
|
||||||
|
unsigned int prefix_len() const
|
||||||
|
{
|
||||||
|
const int ret = prefix_len_32(u.addr);
|
||||||
|
if (ret >= 0)
|
||||||
|
return ret;
|
||||||
|
else
|
||||||
|
throw ipv4_exception("malformed netmask");
|
||||||
|
}
|
||||||
|
|
||||||
|
int prefix_len_nothrow() const
|
||||||
|
{
|
||||||
|
return prefix_len_32(u.addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// number of host bits in netmask
|
||||||
|
unsigned int host_len() const
|
||||||
|
{
|
||||||
|
return SIZE - prefix_len();
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the number of host addresses contained within netmask
|
||||||
|
Addr extent_from_netmask() const
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.u.addr = extent_from_netmask_uint32();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t extent_from_netmask_uint32() const
|
||||||
|
{
|
||||||
|
const unsigned int hl = host_len();
|
||||||
|
if (hl < SIZE)
|
||||||
|
return 1 << hl;
|
||||||
|
else if (hl == SIZE)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
throw ipv4_exception("extent overflow");
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert netmask in addr to prefix_len, will return -1 on error
|
||||||
|
static int prefix_len_32(const std::uint32_t addr)
|
||||||
|
{
|
||||||
|
if (addr == ~std::uint32_t(0))
|
||||||
|
return 32;
|
||||||
|
else if (addr == 0)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned int high = 32;
|
||||||
|
unsigned int low = 1;
|
||||||
|
for (unsigned int i = 0; i < 5; ++i)
|
||||||
|
{
|
||||||
|
const unsigned int mid = (high + low) / 2;
|
||||||
|
const IPv4::Addr::base_type test = prefix_len_to_netmask_unchecked(mid);
|
||||||
|
if (addr == test)
|
||||||
|
return mid;
|
||||||
|
else if (addr > test)
|
||||||
|
low = mid;
|
||||||
|
else
|
||||||
|
high = mid;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// address size in bits
|
||||||
|
static unsigned int size()
|
||||||
|
{
|
||||||
|
return SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t hashval() const
|
||||||
|
{
|
||||||
|
return Hash::value(u.addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef OPENVPN_IP_IMMUTABLE
|
||||||
|
private:
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void negate()
|
||||||
|
{
|
||||||
|
u.addr = ~u.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void zero()
|
||||||
|
{
|
||||||
|
u.addr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void zero_complement()
|
||||||
|
{
|
||||||
|
u.addr = ~0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void one()
|
||||||
|
{
|
||||||
|
u.addr = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr& operator++()
|
||||||
|
{
|
||||||
|
++u.addr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr& operator+=(const long delta)
|
||||||
|
{
|
||||||
|
u.addr += (std::uint32_t)delta;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr& operator-=(const long delta)
|
||||||
|
{
|
||||||
|
return operator+=(-delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static base_type prefix_len_to_netmask_unchecked(const unsigned int prefix_len)
|
||||||
|
{
|
||||||
|
if (prefix_len)
|
||||||
|
return ~((1 << (SIZE - prefix_len)) - 1);
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static base_type prefix_len_to_netmask(const unsigned int prefix_len)
|
||||||
|
{
|
||||||
|
if (prefix_len <= SIZE)
|
||||||
|
return prefix_len_to_netmask_unchecked(prefix_len);
|
||||||
|
else
|
||||||
|
throw ipv4_exception("bad prefix len");
|
||||||
|
}
|
||||||
|
|
||||||
|
union {
|
||||||
|
base_type addr; // host byte order
|
||||||
|
unsigned char bytes[4];
|
||||||
|
} u;
|
||||||
|
};
|
||||||
|
|
||||||
|
OPENVPN_OSTREAM(Addr, to_string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OPENVPN_HASH_METHOD(openvpn::IPv4::Addr, hashval);
|
||||||
|
|
||||||
|
#endif // OPENVPN_ADDR_IPV4_H
|
||||||
@@ -0,0 +1,830 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_ADDR_IPV6_H
|
||||||
|
#define OPENVPN_ADDR_IPV6_H
|
||||||
|
|
||||||
|
#include <cstring> // for std::memcpy, std::memset
|
||||||
|
#include <algorithm> // for std::min
|
||||||
|
#include <cstdint> // for std::uint32_t
|
||||||
|
|
||||||
|
#include <openvpn/io/io.hpp>
|
||||||
|
|
||||||
|
#include <openvpn/common/size.hpp>
|
||||||
|
#include <openvpn/common/exception.hpp>
|
||||||
|
#include <openvpn/common/ostream.hpp>
|
||||||
|
#include <openvpn/common/socktypes.hpp>
|
||||||
|
#include <openvpn/common/ffs.hpp>
|
||||||
|
#include <openvpn/common/hexstr.hpp>
|
||||||
|
#include <openvpn/common/hash.hpp>
|
||||||
|
#include <openvpn/addr/ipv4.hpp>
|
||||||
|
#include <openvpn/addr/iperr.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
namespace IP {
|
||||||
|
class Addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fundamental classes for representing an IPv6 IP address.
|
||||||
|
|
||||||
|
namespace IPv6 {
|
||||||
|
|
||||||
|
OPENVPN_EXCEPTION(ipv6_exception);
|
||||||
|
|
||||||
|
class Addr // NOTE: must be union-legal, so default constructor does not initialize
|
||||||
|
{
|
||||||
|
friend class IP::Addr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum { SIZE=128 };
|
||||||
|
|
||||||
|
static Addr from_addr(const Addr& addr)
|
||||||
|
{
|
||||||
|
return addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_in6_addr(const struct in6_addr *in6)
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
network_to_host_order(&ret.u, (const union ipv6addr *)in6->s6_addr);
|
||||||
|
ret.scope_id_ = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct in6_addr to_in6_addr() const
|
||||||
|
{
|
||||||
|
struct in6_addr ret;
|
||||||
|
host_to_network_order((union ipv6addr *)&ret, &u);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_sockaddr(const struct sockaddr_in6 *sa)
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
network_to_host_order(&ret.u, (const union ipv6addr *)sa->sin6_addr.s6_addr);
|
||||||
|
ret.scope_id_ = sa->sin6_scope_id;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sockaddr_in6 to_sockaddr() const
|
||||||
|
{
|
||||||
|
struct sockaddr_in6 ret;
|
||||||
|
std::memset(&ret, 0, sizeof(ret));
|
||||||
|
ret.sin6_family = AF_INET6;
|
||||||
|
ret.sin6_port = 0;
|
||||||
|
host_to_network_order((union ipv6addr *)&ret.sin6_addr.s6_addr, &u);
|
||||||
|
ret.sin6_scope_id = scope_id_;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_string(const std::string& ipstr, const char *title = nullptr)
|
||||||
|
{
|
||||||
|
openvpn_io::error_code ec;
|
||||||
|
openvpn_io::ip::address_v6 a = openvpn_io::ip::make_address_v6(ipstr, ec);
|
||||||
|
if (ec)
|
||||||
|
throw ipv6_exception(IP::internal::format_error(ipstr, title, "v6", ec));
|
||||||
|
return from_asio(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string() const
|
||||||
|
{
|
||||||
|
const openvpn_io::ip::address_v6 a = to_asio();
|
||||||
|
std::string ret = a.to_string();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_hex(const std::string& s)
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.scope_id_ = 0;
|
||||||
|
ret.zero();
|
||||||
|
size_t len = s.length();
|
||||||
|
size_t base = 0;
|
||||||
|
if (len > 0 && s[len-1] == 'L')
|
||||||
|
len -= 1;
|
||||||
|
if (len >= 2 && s[0] == '0' && s[1] == 'x')
|
||||||
|
{
|
||||||
|
base = 2;
|
||||||
|
len -= 2;
|
||||||
|
}
|
||||||
|
if (len < 1 || len > 32)
|
||||||
|
throw ipv6_exception("parse hex error");
|
||||||
|
size_t di = (len-1)>>1;
|
||||||
|
for (int i = (len & 1) ? -1 : 0; i < int(len); i += 2)
|
||||||
|
{
|
||||||
|
const size_t idx = base + i;
|
||||||
|
const int bh = (i >= 0) ? parse_hex_char(s[idx]) : 0;
|
||||||
|
const int bl = parse_hex_char(s[idx+1]);
|
||||||
|
if (bh == -1 || bl == -1)
|
||||||
|
throw ipv6_exception("parse hex error");
|
||||||
|
ret.u.bytes[Endian::e16(di--)] = (bh<<4) + bl;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_hex() const
|
||||||
|
{
|
||||||
|
std::string ret;
|
||||||
|
ret.reserve(32);
|
||||||
|
bool firstnonzero = false;
|
||||||
|
for (size_t i = 0; i < 16; ++i)
|
||||||
|
{
|
||||||
|
const unsigned char b = u.bytes[Endian::e16rev(i)];
|
||||||
|
if (b || firstnonzero || i == 15)
|
||||||
|
{
|
||||||
|
const char bh = b >> 4;
|
||||||
|
if (bh || firstnonzero)
|
||||||
|
ret += render_hex_char(bh);
|
||||||
|
ret += render_hex_char(b & 0x0F);
|
||||||
|
firstnonzero = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_ulong(unsigned long ul)
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.scope_id_ = 0;
|
||||||
|
ret.u.u64[Endian::e2(0)] = std::uint64_t(ul);
|
||||||
|
ret.u.u64[Endian::e2(1)] = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return *this as a unsigned long
|
||||||
|
unsigned long to_ulong() const
|
||||||
|
{
|
||||||
|
const unsigned long ret = (unsigned long)u.u64[Endian::e2(0)];
|
||||||
|
const std::uint64_t cmp = std::uint64_t(ret);
|
||||||
|
if (u.u64[Endian::e2(1)] || cmp != u.u64[Endian::e2(0)])
|
||||||
|
throw ipv6_exception("overflow in conversion from IPv6.Addr to unsigned long");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_long(long ul)
|
||||||
|
{
|
||||||
|
bool neg = false;
|
||||||
|
Addr ret;
|
||||||
|
ret.scope_id_ = 0;
|
||||||
|
if (ul < 0)
|
||||||
|
{
|
||||||
|
ul = -(ul + 1);
|
||||||
|
neg = true;
|
||||||
|
}
|
||||||
|
ret.u.u64[Endian::e2(0)] = std::uint64_t(ul);
|
||||||
|
ret.u.u64[Endian::e2(1)] = 0;
|
||||||
|
if (neg)
|
||||||
|
ret.negate();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return *this as a long
|
||||||
|
long to_long() const
|
||||||
|
{
|
||||||
|
bool neg = false;
|
||||||
|
Addr a = *this;
|
||||||
|
if (a.u.u64[Endian::e2(1)])
|
||||||
|
{
|
||||||
|
a.negate();
|
||||||
|
neg = true;
|
||||||
|
}
|
||||||
|
const long ret = (long)a.u.u64[Endian::e2(0)];
|
||||||
|
const std::uint64_t cmp = std::uint64_t(ret);
|
||||||
|
if (a.u.u64[Endian::e2(1)] || cmp != a.u.u64[Endian::e2(0)])
|
||||||
|
throw ipv6_exception("overflow in conversion from IPv6.Addr to long");
|
||||||
|
return neg ? -(ret + 1) : ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string arpa() const
|
||||||
|
{
|
||||||
|
throw ipv6_exception("arpa() not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_asio(const openvpn_io::ip::address_v6& asio_addr)
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
union ipv6addr addr;
|
||||||
|
addr.asio_bytes = asio_addr.to_bytes();
|
||||||
|
network_to_host_order(&ret.u, &addr);
|
||||||
|
ret.scope_id_ = (unsigned int)asio_addr.scope_id();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_byte_string(const unsigned char *bytestr)
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
network_to_host_order(&ret.u, (const union ipv6addr *)bytestr);
|
||||||
|
ret.scope_id_ = 0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void to_byte_string(unsigned char *bytestr) const
|
||||||
|
{
|
||||||
|
host_to_network_order((union ipv6addr *)bytestr, &u);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void v4_to_byte_string(unsigned char *bytestr,
|
||||||
|
const std::uint32_t v4addr)
|
||||||
|
{
|
||||||
|
union ipv6addr *a = (union ipv6addr *)bytestr;
|
||||||
|
a->u32[0] = a->u32[1] = a->u32[2] = 0;
|
||||||
|
a->u32[3] = v4addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool byte_string_is_v4(const unsigned char *bytestr)
|
||||||
|
{
|
||||||
|
const union ipv6addr *a = (const union ipv6addr *)bytestr;
|
||||||
|
return a->u32[0] == 0 && a->u32[1] == 0 && a->u32[2] == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::uint32_t v4_from_byte_string(const unsigned char *bytestr)
|
||||||
|
{
|
||||||
|
const union ipv6addr *a = (const union ipv6addr *)bytestr;
|
||||||
|
return a->u32[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
openvpn_io::ip::address_v6 to_asio() const
|
||||||
|
{
|
||||||
|
union ipv6addr addr;
|
||||||
|
host_to_network_order(&addr, &u);
|
||||||
|
return openvpn_io::ip::address_v6(addr.asio_bytes, scope_id_);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_zero()
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.scope_id_ = 0;
|
||||||
|
ret.zero();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_one()
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.scope_id_ = 0;
|
||||||
|
ret.one();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Addr from_zero_complement()
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.scope_id_ = 0;
|
||||||
|
ret.zero_complement();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// build a netmask using given prefix_len
|
||||||
|
static Addr netmask_from_prefix_len(const unsigned int prefix_len)
|
||||||
|
{
|
||||||
|
Addr ret;
|
||||||
|
ret.scope_id_ = 0;
|
||||||
|
ret.prefix_len_to_netmask(prefix_len);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// build a netmask using given extent
|
||||||
|
Addr netmask_from_extent() const
|
||||||
|
{
|
||||||
|
const Addr lb = *this - 1;
|
||||||
|
for (size_t i = 4; i --> 0 ;)
|
||||||
|
{
|
||||||
|
const std::uint32_t v = lb.u.u32[Endian::e4(i)];
|
||||||
|
if (v)
|
||||||
|
return netmask_from_prefix_len(SIZE - (((unsigned int)i<<5) + find_last_set(v)));
|
||||||
|
}
|
||||||
|
return from_zero_complement();
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator&(const Addr& other) const {
|
||||||
|
Addr ret;
|
||||||
|
ret.scope_id_ = scope_id_;
|
||||||
|
ret.u.u64[0] = u.u64[0] & other.u.u64[0];
|
||||||
|
ret.u.u64[1] = u.u64[1] & other.u.u64[1];
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator|(const Addr& other) const {
|
||||||
|
Addr ret;
|
||||||
|
ret.scope_id_ = scope_id_;
|
||||||
|
ret.u.u64[0] = u.u64[0] | other.u.u64[0];
|
||||||
|
ret.u.u64[1] = u.u64[1] | other.u.u64[1];
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator+(const long delta) const {
|
||||||
|
Addr ret = *this;
|
||||||
|
ret.u.u64[Endian::e2(0)] += delta;
|
||||||
|
ret.u.u64[Endian::e2(1)] += (delta >= 0)
|
||||||
|
? (ret.u.u64[Endian::e2(0)] < u.u64[Endian::e2(0)])
|
||||||
|
: -(ret.u.u64[Endian::e2(0)] > u.u64[Endian::e2(0)]);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator+(const Addr& other) const {
|
||||||
|
Addr ret = *this;
|
||||||
|
add(ret.u, other.u);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator-(const long delta) const {
|
||||||
|
return operator+(-delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator-(const Addr& other) const {
|
||||||
|
Addr ret = *this;
|
||||||
|
sub(ret.u, other.u);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator*(const Addr& d) const {
|
||||||
|
Addr m = d;
|
||||||
|
Addr ret = from_zero();
|
||||||
|
for (unsigned int i = 0; i < SIZE; ++i)
|
||||||
|
{
|
||||||
|
if (bit(i))
|
||||||
|
ret += m;
|
||||||
|
m <<= 1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator/(const Addr& d) const {
|
||||||
|
Addr q, r;
|
||||||
|
div(*this, d, q, r);
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator%(const Addr& d) const {
|
||||||
|
Addr q, r;
|
||||||
|
div(*this, d, q, r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator<<(const unsigned int shift) const {
|
||||||
|
Addr ret = *this;
|
||||||
|
shiftl128(ret.u.u64[Endian::e2(0)],
|
||||||
|
ret.u.u64[Endian::e2(1)],
|
||||||
|
shift);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator>>(const unsigned int shift) const {
|
||||||
|
Addr ret = *this;
|
||||||
|
shiftr128(ret.u.u64[Endian::e2(0)],
|
||||||
|
ret.u.u64[Endian::e2(1)],
|
||||||
|
shift);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr operator~() const {
|
||||||
|
Addr ret;
|
||||||
|
ret.scope_id_ = scope_id_;
|
||||||
|
ret.u.u64[0] = ~u.u64[0];
|
||||||
|
ret.u.u64[1] = ~u.u64[1];
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the network that contains the current address
|
||||||
|
Addr network_addr(const unsigned int prefix_len) const
|
||||||
|
{
|
||||||
|
return *this & netmask_from_prefix_len(prefix_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Addr& other) const
|
||||||
|
{
|
||||||
|
return u.u64[0] == other.u.u64[0] && u.u64[1] == other.u.u64[1] && scope_id_ == other.scope_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const Addr& other) const
|
||||||
|
{
|
||||||
|
return !operator==(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OPENVPN_IPV6_OPERATOR_REL(OP) \
|
||||||
|
bool operator OP(const Addr& other) const \
|
||||||
|
{ \
|
||||||
|
if (u.u64[Endian::e2(1)] == other.u.u64[Endian::e2(1)]) \
|
||||||
|
{ \
|
||||||
|
if (u.u64[Endian::e2(0)] != other.u.u64[Endian::e2(0)]) \
|
||||||
|
return u.u64[Endian::e2(0)] OP other.u.u64[Endian::e2(0)]; \
|
||||||
|
else \
|
||||||
|
return scope_id_ OP other.scope_id_; \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
return u.u64[Endian::e2(1)] OP other.u.u64[Endian::e2(1)]; \
|
||||||
|
}
|
||||||
|
|
||||||
|
OPENVPN_IPV6_OPERATOR_REL(<)
|
||||||
|
OPENVPN_IPV6_OPERATOR_REL(>)
|
||||||
|
OPENVPN_IPV6_OPERATOR_REL(<=)
|
||||||
|
OPENVPN_IPV6_OPERATOR_REL(>=)
|
||||||
|
|
||||||
|
#undef OPENVPN_IPV6_OPERATOR_REL
|
||||||
|
|
||||||
|
bool unspecified() const
|
||||||
|
{
|
||||||
|
return all_zeros();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool specified() const
|
||||||
|
{
|
||||||
|
return !unspecified();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool all_zeros() const
|
||||||
|
{
|
||||||
|
return u.u64[0] == 0 && u.u64[1] == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool all_ones() const
|
||||||
|
{
|
||||||
|
return u.u64[0] == ~std::uint64_t(0) && u.u64[1] == ~std::uint64_t(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_loopback() const // ::1
|
||||||
|
{
|
||||||
|
return u.u64[Endian::e2(1)] == 0 && u.u64[Endian::e2(0)] == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool bit(unsigned int pos) const
|
||||||
|
{
|
||||||
|
if (pos < 64)
|
||||||
|
return (u.u64[Endian::e2(0)] & (std::uint64_t(1)<<pos)) != 0;
|
||||||
|
else
|
||||||
|
return (u.u64[Endian::e2(1)] & (std::uint64_t(1)<<(pos-64))) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// number of network bits in netmask,
|
||||||
|
// throws exception if addr is not a netmask
|
||||||
|
unsigned int prefix_len() const
|
||||||
|
{
|
||||||
|
int idx = -1;
|
||||||
|
|
||||||
|
if (u.u32[Endian::e4(3)] != ~std::uint32_t(0))
|
||||||
|
{
|
||||||
|
if (!u.u32[Endian::e4(0)] && !u.u32[Endian::e4(1)] && !u.u32[Endian::e4(2)])
|
||||||
|
idx = 0;
|
||||||
|
}
|
||||||
|
else if (u.u32[Endian::e4(2)] != ~std::uint32_t(0))
|
||||||
|
{
|
||||||
|
if (!u.u32[Endian::e4(0)] && !u.u32[Endian::e4(1)])
|
||||||
|
idx = 1;
|
||||||
|
}
|
||||||
|
else if (u.u32[Endian::e4(1)] != ~std::uint32_t(0))
|
||||||
|
{
|
||||||
|
if (!u.u32[Endian::e4(0)])
|
||||||
|
idx = 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
idx = 3;
|
||||||
|
|
||||||
|
if (idx >= 0)
|
||||||
|
{
|
||||||
|
const int ret = IPv4::Addr::prefix_len_32(u.u32[Endian::e4rev(idx)]);
|
||||||
|
if (ret >= 0)
|
||||||
|
return ret + (idx<<5);
|
||||||
|
}
|
||||||
|
throw ipv6_exception("malformed netmask");
|
||||||
|
}
|
||||||
|
|
||||||
|
// number of host bits in netmask
|
||||||
|
unsigned int host_len() const
|
||||||
|
{
|
||||||
|
return SIZE - prefix_len();
|
||||||
|
}
|
||||||
|
|
||||||
|
// return the number of host addresses contained within netmask
|
||||||
|
Addr extent_from_netmask() const
|
||||||
|
{
|
||||||
|
const unsigned int hl = host_len();
|
||||||
|
if (hl < SIZE)
|
||||||
|
{
|
||||||
|
Addr a;
|
||||||
|
a.scope_id_ = 0;
|
||||||
|
a.one();
|
||||||
|
return a << hl;
|
||||||
|
}
|
||||||
|
else if (hl == SIZE)
|
||||||
|
return from_zero();
|
||||||
|
else
|
||||||
|
throw ipv6_exception("extent overflow");
|
||||||
|
}
|
||||||
|
|
||||||
|
// address size in bits
|
||||||
|
static unsigned int size()
|
||||||
|
{
|
||||||
|
return SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t hashval() const
|
||||||
|
{
|
||||||
|
return Hash::value(u.u32[0], u.u32[1], u.u32[2], u.u32[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef OPENVPN_IP_IMMUTABLE
|
||||||
|
private:
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void negate()
|
||||||
|
{
|
||||||
|
u.u64[0] = ~u.u64[0];
|
||||||
|
u.u64[1] = ~u.u64[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void zero()
|
||||||
|
{
|
||||||
|
u.u64[0] = 0;
|
||||||
|
u.u64[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void zero_complement()
|
||||||
|
{
|
||||||
|
u.u64[0] = ~std::uint64_t(0);
|
||||||
|
u.u64[1] = ~std::uint64_t(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void one()
|
||||||
|
{
|
||||||
|
u.u64[0] = 1;
|
||||||
|
u.u64[1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr& operator++()
|
||||||
|
{
|
||||||
|
if (++u.u64[Endian::e2(0)] == 0)
|
||||||
|
++u.u64[Endian::e2(1)];
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr& operator+=(const long delta)
|
||||||
|
{
|
||||||
|
*this = *this + delta;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr& operator-=(const long delta)
|
||||||
|
{
|
||||||
|
return operator+=(-delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr& operator+=(const Addr& other) {
|
||||||
|
add(u, other.u);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr& operator-=(const Addr& other) {
|
||||||
|
sub(u, other.u);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr& operator<<=(const unsigned int shift) {
|
||||||
|
shiftl128(u.u64[Endian::e2(0)],
|
||||||
|
u.u64[Endian::e2(1)],
|
||||||
|
shift);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Addr& operator>>=(const unsigned int shift) {
|
||||||
|
shiftr128(u.u64[Endian::e2(0)],
|
||||||
|
u.u64[Endian::e2(1)],
|
||||||
|
shift);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_clear_bit(unsigned int pos, bool value)
|
||||||
|
{
|
||||||
|
if (pos < 64)
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
u.u64[Endian::e2(0)] |= (std::uint64_t(1)<<pos);
|
||||||
|
else
|
||||||
|
u.u64[Endian::e2(0)] &= ~(std::uint64_t(1)<<pos);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
u.u64[Endian::e2(1)] |= (std::uint64_t(1)<<(pos-64));
|
||||||
|
else
|
||||||
|
u.u64[Endian::e2(1)] &= ~(std::uint64_t(1)<<(pos-64));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_bit(unsigned int pos, bool value)
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
if (pos < 64)
|
||||||
|
u.u64[Endian::e2(0)] |= (std::uint64_t(1)<<pos);
|
||||||
|
else
|
||||||
|
u.u64[Endian::e2(1)] |= (std::uint64_t(1)<<(pos-64));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void div(const Addr& n, const Addr& d, Addr& q, Addr& r)
|
||||||
|
{
|
||||||
|
if (d.all_zeros())
|
||||||
|
throw ipv6_exception("division by 0");
|
||||||
|
q = from_zero(); // quotient
|
||||||
|
r = n; // remainder (init to numerator)
|
||||||
|
Addr ml = from_zero(); // mask low
|
||||||
|
Addr mh = d; // mask high (init to denominator)
|
||||||
|
for (unsigned int i = 0; i < SIZE; ++i)
|
||||||
|
{
|
||||||
|
ml >>= 1;
|
||||||
|
ml.set_bit(SIZE-1, mh.bit(0));
|
||||||
|
mh >>= 1;
|
||||||
|
if (mh.all_zeros() && r >= ml)
|
||||||
|
{
|
||||||
|
r -= ml;
|
||||||
|
q.set_bit((SIZE-1)-i, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int scope_id() const
|
||||||
|
{
|
||||||
|
return scope_id_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
union ipv6addr {
|
||||||
|
std::uint64_t u64[2];
|
||||||
|
std::uint32_t u32[4]; // generally stored in host byte order
|
||||||
|
unsigned char bytes[16];
|
||||||
|
openvpn_io::ip::address_v6::bytes_type asio_bytes;
|
||||||
|
};
|
||||||
|
|
||||||
|
void prefix_len_to_netmask_unchecked(const unsigned int prefix_len)
|
||||||
|
{
|
||||||
|
if (prefix_len > 0)
|
||||||
|
{
|
||||||
|
const unsigned int pl = prefix_len - 1;
|
||||||
|
const std::uint32_t mask = ~((1 << (31 - (pl & 31))) - 1);
|
||||||
|
switch (pl >> 5)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
u.u32[Endian::e4(0)] = 0;
|
||||||
|
u.u32[Endian::e4(1)] = 0;
|
||||||
|
u.u32[Endian::e4(2)] = 0;
|
||||||
|
u.u32[Endian::e4(3)] = mask;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
u.u32[Endian::e4(0)] = 0;
|
||||||
|
u.u32[Endian::e4(1)] = 0;
|
||||||
|
u.u32[Endian::e4(2)] = mask;
|
||||||
|
u.u32[Endian::e4(3)] = ~0;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
u.u32[Endian::e4(0)] = 0;
|
||||||
|
u.u32[Endian::e4(1)] = mask;
|
||||||
|
u.u32[Endian::e4(2)] = ~0;
|
||||||
|
u.u32[Endian::e4(3)] = ~0;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
u.u32[Endian::e4(0)] = mask;
|
||||||
|
u.u32[Endian::e4(1)] = ~0;
|
||||||
|
u.u32[Endian::e4(2)] = ~0;
|
||||||
|
u.u32[Endian::e4(3)] = ~0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
zero();
|
||||||
|
}
|
||||||
|
|
||||||
|
void prefix_len_to_netmask(const unsigned int prefix_len)
|
||||||
|
{
|
||||||
|
if (prefix_len <= SIZE)
|
||||||
|
return prefix_len_to_netmask_unchecked(prefix_len);
|
||||||
|
else
|
||||||
|
throw ipv6_exception("bad prefix len");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void host_to_network_order(union ipv6addr *dest, const union ipv6addr *src)
|
||||||
|
{
|
||||||
|
dest->u32[0] = htonl(src->u32[Endian::e4rev(0)]);
|
||||||
|
dest->u32[1] = htonl(src->u32[Endian::e4rev(1)]);
|
||||||
|
dest->u32[2] = htonl(src->u32[Endian::e4rev(2)]);
|
||||||
|
dest->u32[3] = htonl(src->u32[Endian::e4rev(3)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void network_to_host_order(union ipv6addr *dest, const union ipv6addr *src)
|
||||||
|
{
|
||||||
|
dest->u32[0] = ntohl(src->u32[Endian::e4rev(0)]);
|
||||||
|
dest->u32[1] = ntohl(src->u32[Endian::e4rev(1)]);
|
||||||
|
dest->u32[2] = ntohl(src->u32[Endian::e4rev(2)]);
|
||||||
|
dest->u32[3] = ntohl(src->u32[Endian::e4rev(3)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void shiftl128(std::uint64_t& low,
|
||||||
|
std::uint64_t& high,
|
||||||
|
unsigned int shift)
|
||||||
|
{
|
||||||
|
if (shift == 1)
|
||||||
|
{
|
||||||
|
high <<= 1;
|
||||||
|
if (low & (std::uint64_t(1) << 63))
|
||||||
|
high |= 1;
|
||||||
|
low <<= 1;
|
||||||
|
}
|
||||||
|
else if (shift == 0)
|
||||||
|
;
|
||||||
|
else if (shift <= 128)
|
||||||
|
{
|
||||||
|
if (shift >= 64)
|
||||||
|
{
|
||||||
|
high = low;
|
||||||
|
low = 0;
|
||||||
|
shift -= 64;
|
||||||
|
}
|
||||||
|
if (shift < 64)
|
||||||
|
{
|
||||||
|
high = (high << shift) | (low >> (64-shift));
|
||||||
|
low <<= shift;
|
||||||
|
}
|
||||||
|
else // shift == 64
|
||||||
|
high = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw ipv6_exception("l-shift too large");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void shiftr128(std::uint64_t& low,
|
||||||
|
std::uint64_t& high,
|
||||||
|
unsigned int shift)
|
||||||
|
{
|
||||||
|
if (shift == 1)
|
||||||
|
{
|
||||||
|
low >>= 1;
|
||||||
|
if (high & 1)
|
||||||
|
low |= (std::uint64_t(1) << 63);
|
||||||
|
high >>= 1;
|
||||||
|
}
|
||||||
|
else if (shift == 0)
|
||||||
|
;
|
||||||
|
else if (shift <= 128)
|
||||||
|
{
|
||||||
|
if (shift >= 64)
|
||||||
|
{
|
||||||
|
low = high;
|
||||||
|
high = 0;
|
||||||
|
shift -= 64;
|
||||||
|
}
|
||||||
|
if (shift < 64)
|
||||||
|
{
|
||||||
|
low = (low >> shift) | (high << (64-shift));
|
||||||
|
high >>= shift;
|
||||||
|
}
|
||||||
|
else // shift == 64
|
||||||
|
low = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw ipv6_exception("r-shift too large");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add(ipv6addr& dest, const ipv6addr& src) {
|
||||||
|
const std::uint64_t dorigl = dest.u64[Endian::e2(0)];
|
||||||
|
dest.u64[Endian::e2(0)] += src.u64[Endian::e2(0)];
|
||||||
|
dest.u64[Endian::e2(1)] += src.u64[Endian::e2(1)];
|
||||||
|
// check for overflow of low 64 bits, add carry to high
|
||||||
|
if (dest.u64[Endian::e2(0)] < dorigl)
|
||||||
|
++dest.u64[Endian::e2(1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sub(ipv6addr& dest, const ipv6addr& src) {
|
||||||
|
const std::uint64_t dorigl = dest.u64[Endian::e2(0)];
|
||||||
|
dest.u64[Endian::e2(0)] -= src.u64[Endian::e2(0)];
|
||||||
|
dest.u64[Endian::e2(1)] -= src.u64[Endian::e2(1)]
|
||||||
|
+ (dorigl < dest.u64[Endian::e2(0)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
union ipv6addr u;
|
||||||
|
unsigned int scope_id_;
|
||||||
|
};
|
||||||
|
|
||||||
|
OPENVPN_OSTREAM(Addr, to_string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OPENVPN_HASH_METHOD(openvpn::IPv6::Addr, hashval);
|
||||||
|
|
||||||
|
#endif // OPENVPN_ADDR_IPV6_H
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_ADDR_MACADDR_H
|
||||||
|
#define OPENVPN_ADDR_MACADDR_H
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <openvpn/common/exception.hpp>
|
||||||
|
#include <openvpn/common/ostream.hpp>
|
||||||
|
#include <openvpn/common/hexstr.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
|
||||||
|
// Fundamental class for representing an ethernet MAC address.
|
||||||
|
|
||||||
|
class MACAddr {
|
||||||
|
public:
|
||||||
|
MACAddr()
|
||||||
|
{
|
||||||
|
std::memset(addr_, 0, sizeof(addr_));
|
||||||
|
}
|
||||||
|
|
||||||
|
MACAddr(const unsigned char *addr)
|
||||||
|
{
|
||||||
|
reset(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset(const unsigned char *addr)
|
||||||
|
{
|
||||||
|
std::memcpy(addr_, addr, sizeof(addr_));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string() const
|
||||||
|
{
|
||||||
|
return render_hex_sep(addr_, sizeof(addr_), ':');
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned char addr_[6];
|
||||||
|
};
|
||||||
|
|
||||||
|
OPENVPN_OSTREAM(MACAddr, to_string)
|
||||||
|
|
||||||
|
} // namespace openvpn
|
||||||
|
|
||||||
|
#endif // OPENVPN_ADDR_MACADDR_H
|
||||||
@@ -0,0 +1,138 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_ADDR_POOL_H
|
||||||
|
#define OPENVPN_ADDR_POOL_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <deque>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include <openvpn/common/size.hpp>
|
||||||
|
#include <openvpn/common/exception.hpp>
|
||||||
|
|
||||||
|
#include <openvpn/addr/ip.hpp>
|
||||||
|
#include <openvpn/addr/range.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
namespace IP {
|
||||||
|
|
||||||
|
// Maintain a pool of IP addresses.
|
||||||
|
// A should be IP::Addr, IPv4::Addr, or IPv6::Addr.
|
||||||
|
template <typename ADDR>
|
||||||
|
class PoolType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PoolType() {}
|
||||||
|
|
||||||
|
// Add range of addresses to pool (pool will own the addresses).
|
||||||
|
void add_range(const RangeType<ADDR>& range)
|
||||||
|
{
|
||||||
|
typename RangeType<ADDR>::Iterator iter = range.iterator();
|
||||||
|
while (iter.more())
|
||||||
|
{
|
||||||
|
const ADDR& a = iter.addr();
|
||||||
|
add_addr(a);
|
||||||
|
iter.next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add single address to pool (pool will own the address).
|
||||||
|
void add_addr(const ADDR& addr)
|
||||||
|
{
|
||||||
|
typename std::unordered_map<ADDR, bool>::const_iterator e = map.find(addr);
|
||||||
|
if (e == map.end())
|
||||||
|
{
|
||||||
|
freelist.push_back(addr);
|
||||||
|
map[addr] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return number of pool addresses currently in use.
|
||||||
|
size_t n_in_use() const
|
||||||
|
{
|
||||||
|
return map.size() - freelist.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acquire an address from pool. Returns true if successful,
|
||||||
|
// with address placed in dest, or false if pool depleted.
|
||||||
|
bool acquire_addr(ADDR& dest)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (freelist.empty())
|
||||||
|
return false;
|
||||||
|
const ADDR& a = freelist.front();
|
||||||
|
typename std::unordered_map<ADDR, bool>::iterator e = map.find(a);
|
||||||
|
if (e == map.end()) // any address in freelist must exist in map
|
||||||
|
throw Exception("PoolType: address in freelist doesn't exist in map");
|
||||||
|
if (!e->second)
|
||||||
|
{
|
||||||
|
e->second = true;
|
||||||
|
dest = a;
|
||||||
|
freelist.pop_front();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
freelist.pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Acquire a specific address from pool, returning true if
|
||||||
|
// successful, or false if the address is not available.
|
||||||
|
bool acquire_specific_addr(const ADDR& addr)
|
||||||
|
{
|
||||||
|
typename std::unordered_map<ADDR, bool>::iterator e = map.find(addr);
|
||||||
|
if (e != map.end() && !e->second)
|
||||||
|
{
|
||||||
|
e->second = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a previously acquired address to the pool. Does nothing if
|
||||||
|
// (a) the address is owned by the pool and marked as free, or
|
||||||
|
// (b) the address is not owned by the pool.
|
||||||
|
void release_addr(const ADDR& addr)
|
||||||
|
{
|
||||||
|
typename std::unordered_map<ADDR, bool>::iterator e = map.find(addr);
|
||||||
|
if (e != map.end() && e->second)
|
||||||
|
{
|
||||||
|
freelist.push_back(addr);
|
||||||
|
e->second = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DEBUGGING -- get the map load factor
|
||||||
|
float load_factor() const { return map.load_factor(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::deque<ADDR> freelist;
|
||||||
|
std::unordered_map<ADDR, bool> map;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef PoolType<IP::Addr> Pool;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,137 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_ADDR_RANGE_H
|
||||||
|
#define OPENVPN_ADDR_RANGE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <openvpn/common/size.hpp>
|
||||||
|
#include <openvpn/common/exception.hpp>
|
||||||
|
|
||||||
|
#include <openvpn/addr/ip.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
namespace IP {
|
||||||
|
|
||||||
|
// Denote a range of IP addresses with a start and extent,
|
||||||
|
// where A represents an address class.
|
||||||
|
// A should be a network address class such as IP::Addr, IPv4::Addr, or IPv6::Addr.
|
||||||
|
|
||||||
|
template <typename ADDR>
|
||||||
|
class RangeType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
class Iterator
|
||||||
|
{
|
||||||
|
friend class RangeType;
|
||||||
|
public:
|
||||||
|
bool more() const { return remaining_ > 0; }
|
||||||
|
|
||||||
|
const ADDR& addr() const { return addr_; }
|
||||||
|
|
||||||
|
void next()
|
||||||
|
{
|
||||||
|
if (more())
|
||||||
|
{
|
||||||
|
++addr_;
|
||||||
|
--remaining_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Iterator(const RangeType& range)
|
||||||
|
: addr_(range.start_), remaining_(range.extent_) {}
|
||||||
|
|
||||||
|
ADDR addr_;
|
||||||
|
size_t remaining_;
|
||||||
|
};
|
||||||
|
|
||||||
|
RangeType() : extent_(0) {}
|
||||||
|
|
||||||
|
RangeType(const ADDR& start, const size_t extent)
|
||||||
|
: start_(start), extent_(extent) {}
|
||||||
|
|
||||||
|
Iterator iterator() const { return Iterator(*this); }
|
||||||
|
|
||||||
|
const bool defined() const { return extent_ > 0; }
|
||||||
|
const ADDR& start() const { return start_; }
|
||||||
|
size_t extent() const { return extent_; }
|
||||||
|
|
||||||
|
RangeType pull_front(size_t extent)
|
||||||
|
{
|
||||||
|
if (extent > extent_)
|
||||||
|
extent = extent_;
|
||||||
|
RangeType ret(start_, extent);
|
||||||
|
start_ += extent;
|
||||||
|
extent_ -= extent;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string() const
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
os << start_.to_string() << '[' << extent_ << ']';
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ADDR start_;
|
||||||
|
size_t extent_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ADDR>
|
||||||
|
class RangePartitionType
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RangePartitionType(const RangeType<ADDR>& src_range, const size_t n_partitions)
|
||||||
|
: range(src_range),
|
||||||
|
remaining(n_partitions)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool next(RangeType<ADDR>& r)
|
||||||
|
{
|
||||||
|
if (remaining)
|
||||||
|
{
|
||||||
|
if (remaining > 1)
|
||||||
|
r = range.pull_front(range.extent() / remaining);
|
||||||
|
else
|
||||||
|
r = range;
|
||||||
|
--remaining;
|
||||||
|
return r.defined();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
RangeType<ADDR> range;
|
||||||
|
size_t remaining;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef RangeType<IP::Addr> Range;
|
||||||
|
typedef RangePartitionType<IP::Addr> RangePartition;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
// Regular expressions for IPv4/v6
|
||||||
|
// Source: http://stackoverflow.com/questions/53497/regular-expression-that-matches-valid-ipv6-addresses
|
||||||
|
|
||||||
|
#ifndef OPENVPN_ADDR_REGEX_H
|
||||||
|
#define OPENVPN_ADDR_REGEX_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
namespace IP {
|
||||||
|
inline std::string v4_regex()
|
||||||
|
{
|
||||||
|
const std::string ipv4seg = "(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])";
|
||||||
|
return "(?:" + ipv4seg + "\\.){3,3}" + ipv4seg;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string v6_regex()
|
||||||
|
{
|
||||||
|
const std::string ipv6seg = "[0-9a-fA-F]{1,4}";
|
||||||
|
return "(?:"
|
||||||
|
"(?:" + ipv6seg + ":){7,7}" + ipv6seg + "|" // 1:2:3:4:5:6:7:8
|
||||||
|
"(?:" + ipv6seg + ":){1,7}:|" // 1:: 1:2:3:4:5:6:7::
|
||||||
|
"(?:" + ipv6seg + ":){1,6}:" + ipv6seg + "|" // 1::8 1:2:3:4:5:6::8 1:2:3:4:5:6::8
|
||||||
|
"(?:" + ipv6seg + ":){1,5}(?::" + ipv6seg + "){1,2}|" // 1::7:8 1:2:3:4:5::7:8 1:2:3:4:5::8
|
||||||
|
"(?:" + ipv6seg + ":){1,4}(?::" + ipv6seg + "){1,3}|" // 1::6:7:8 1:2:3:4::6:7:8 1:2:3:4::8
|
||||||
|
"(?:" + ipv6seg + ":){1,3}(?::" + ipv6seg + "){1,4}|" // 1::5:6:7:8 1:2:3::5:6:7:8 1:2:3::8
|
||||||
|
"(?:" + ipv6seg + ":){1,2}(?::" + ipv6seg + "){1,5}|" + // 1::4:5:6:7:8 1:2::4:5:6:7:8 1:2::8
|
||||||
|
ipv6seg + ":(?:(?::" + ipv6seg + "){1,6})|" // 1::3:4:5:6:7:8 1::3:4:5:6:7:8 1::8
|
||||||
|
":(?:(?::" + ipv6seg + "){1,7}|:)|" // ::2:3:4:5:6:7:8 ::2:3:4:5:6:7:8 ::8 ::
|
||||||
|
"fe80:(?::" + ipv6seg + "){0,4}%[0-9a-zA-Z]{1,}|" // fe80::7:8%eth0 fe80::7:8%1 (link-local IPv6 addresses with zone index)
|
||||||
|
"::(?:ffff(?::0{1,4}){0,1}:){0,1}" + v4_regex() + "|" // ::255.255.255.255 ::ffff:255.255.255.255 ::ffff:0:255.255.255.255 (IPv4-mapped IPv6 addresses and IPv4-translated addresses)
|
||||||
|
"(?:" + ipv6seg + ":){1,4}:" + v4_regex() + // 2001:db8:3:4::192.0.2.33 64:ff9b::192.0.2.33 (IPv4-Embedded IPv6 Address)
|
||||||
|
")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,260 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_ADDR_ROUTE_H
|
||||||
|
#define OPENVPN_ADDR_ROUTE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdint> // for std::uint32_t
|
||||||
|
|
||||||
|
#include <openvpn/common/size.hpp>
|
||||||
|
#include <openvpn/common/exception.hpp>
|
||||||
|
#include <openvpn/common/number.hpp>
|
||||||
|
#include <openvpn/common/to_string.hpp>
|
||||||
|
#include <openvpn/common/split.hpp>
|
||||||
|
#include <openvpn/common/hash.hpp>
|
||||||
|
#include <openvpn/addr/ip.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
namespace IP {
|
||||||
|
// Basic route object
|
||||||
|
template <typename ADDR>
|
||||||
|
struct RouteType
|
||||||
|
{
|
||||||
|
typedef ADDR Addr;
|
||||||
|
|
||||||
|
ADDR addr;
|
||||||
|
unsigned int prefix_len;
|
||||||
|
|
||||||
|
OPENVPN_EXCEPTION(route_error);
|
||||||
|
|
||||||
|
RouteType()
|
||||||
|
: prefix_len(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RouteType(const std::string& rtstr, const char *title = nullptr)
|
||||||
|
: RouteType(RouteType::from_string(rtstr, title))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RouteType(const std::string& rtstr, const std::string& title)
|
||||||
|
: RouteType(RouteType::from_string(rtstr, title.c_str()))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RouteType(const ADDR& addr_arg,
|
||||||
|
const unsigned int prefix_len_arg)
|
||||||
|
: addr(addr_arg),
|
||||||
|
prefix_len(prefix_len_arg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static RouteType from_string(const std::string& rtstr, const char *title = nullptr)
|
||||||
|
{
|
||||||
|
RouteType r;
|
||||||
|
std::vector<std::string> pair;
|
||||||
|
pair.reserve(2);
|
||||||
|
Split::by_char_void<std::vector<std::string>, NullLex, Split::NullLimit>(pair, rtstr, '/', 0, 1);
|
||||||
|
r.addr = ADDR::from_string(pair[0], title);
|
||||||
|
if (pair.size() >= 2)
|
||||||
|
{
|
||||||
|
r.prefix_len = parse_number_throw<unsigned int>(pair[1], "prefix length");
|
||||||
|
if (r.prefix_len > r.addr.size())
|
||||||
|
OPENVPN_THROW(route_error, (title ? title : "route") << " : bad prefix length : " << rtstr);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
r.prefix_len = r.addr.size();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
IP::Addr::Version version() const
|
||||||
|
{
|
||||||
|
return addr.version();
|
||||||
|
}
|
||||||
|
|
||||||
|
IP::Addr::VersionMask version_mask() const
|
||||||
|
{
|
||||||
|
return addr.version_mask();
|
||||||
|
}
|
||||||
|
|
||||||
|
ADDR netmask() const
|
||||||
|
{
|
||||||
|
return ADDR::netmask_from_prefix_len(version(), prefix_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t extent() const
|
||||||
|
{
|
||||||
|
return netmask().extent_from_netmask().to_ulong();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_canonical() const
|
||||||
|
{
|
||||||
|
return (addr & netmask()) == addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void force_canonical()
|
||||||
|
{
|
||||||
|
addr = addr & netmask();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_host() const
|
||||||
|
{
|
||||||
|
return addr.defined() && prefix_len == addr.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(const ADDR& a) const // assumes canonical address/routes
|
||||||
|
{
|
||||||
|
if (addr.defined() && addr.version() == a.version())
|
||||||
|
return (a & netmask()) == addr;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(const RouteType& r) const // assumes canonical routes
|
||||||
|
{
|
||||||
|
return contains(r.addr) && r.prefix_len >= prefix_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool split(RouteType& r1, RouteType& r2) const // assumes we are canonical
|
||||||
|
{
|
||||||
|
if (!is_host())
|
||||||
|
{
|
||||||
|
const unsigned int newpl = prefix_len + 1;
|
||||||
|
r1.addr = addr;
|
||||||
|
r1.prefix_len = newpl;
|
||||||
|
|
||||||
|
r2.addr = addr + ADDR::netmask_from_prefix_len(addr.version(), newpl).extent_from_netmask();
|
||||||
|
r2.prefix_len = newpl;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string() const
|
||||||
|
{
|
||||||
|
return addr.to_string() + '/' + openvpn::to_string(prefix_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string_by_netmask() const
|
||||||
|
{
|
||||||
|
return addr.to_string() + ' ' + netmask().to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const RouteType& other) const
|
||||||
|
{
|
||||||
|
return prefix_len == other.prefix_len && addr == other.addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t hash_value() const
|
||||||
|
{
|
||||||
|
return Hash::value(addr, prefix_len);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename ADDR>
|
||||||
|
struct RouteTypeList : public std::vector<RouteType<ADDR>>
|
||||||
|
{
|
||||||
|
typedef std::vector< RouteType<ADDR> > Base;
|
||||||
|
|
||||||
|
OPENVPN_EXCEPTION(route_list_error);
|
||||||
|
|
||||||
|
std::string to_string() const
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
for (auto &r : *this)
|
||||||
|
os << r.to_string() << std::endl;
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
IP::Addr::VersionMask version_mask() const
|
||||||
|
{
|
||||||
|
IP::Addr::VersionMask mask = 0;
|
||||||
|
for (auto &r : *this)
|
||||||
|
mask |= r.version_mask();
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
void verify_canonical() const
|
||||||
|
{
|
||||||
|
for (auto &r : *this)
|
||||||
|
if (!r.is_canonical())
|
||||||
|
throw route_list_error("route not canonical: " + r.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename R>
|
||||||
|
bool contains(const R& c) const
|
||||||
|
{
|
||||||
|
for (auto &r : *this)
|
||||||
|
if (r.contains(c))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef RouteType<IP::Addr> Route;
|
||||||
|
typedef RouteType<IPv4::Addr> Route4;
|
||||||
|
typedef RouteType<IPv6::Addr> Route6;
|
||||||
|
|
||||||
|
typedef RouteTypeList<IP::Addr> RouteList;
|
||||||
|
typedef RouteTypeList<IPv4::Addr> Route4List;
|
||||||
|
typedef RouteTypeList<IPv6::Addr> Route6List;
|
||||||
|
|
||||||
|
OPENVPN_OSTREAM(Route, to_string);
|
||||||
|
OPENVPN_OSTREAM(Route4, to_string);
|
||||||
|
OPENVPN_OSTREAM(Route6, to_string);
|
||||||
|
|
||||||
|
OPENVPN_OSTREAM(RouteList, to_string);
|
||||||
|
OPENVPN_OSTREAM(Route4List, to_string);
|
||||||
|
OPENVPN_OSTREAM(Route6List, to_string);
|
||||||
|
|
||||||
|
inline Route route_from_string_prefix(const std::string& addrstr,
|
||||||
|
const unsigned int prefix_len,
|
||||||
|
const std::string& title,
|
||||||
|
const IP::Addr::Version required_version = IP::Addr::UNSPEC)
|
||||||
|
{
|
||||||
|
Route r;
|
||||||
|
r.addr = IP::Addr(addrstr, title, required_version);
|
||||||
|
r.prefix_len = prefix_len;
|
||||||
|
if (r.prefix_len > r.addr.size())
|
||||||
|
OPENVPN_THROW(Route::route_error, title << " : bad prefix length : " << addrstr);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Route route_from_string(const std::string& rtstr,
|
||||||
|
const std::string& title,
|
||||||
|
const IP::Addr::Version required_version = IP::Addr::UNSPEC)
|
||||||
|
{
|
||||||
|
Route r(rtstr, title);
|
||||||
|
r.addr.validate_version(title, required_version);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OPENVPN_HASH_METHOD(openvpn::IP::Route, hash_value);
|
||||||
|
OPENVPN_HASH_METHOD(openvpn::IP::Route4, hash_value);
|
||||||
|
OPENVPN_HASH_METHOD(openvpn::IP::Route6, hash_value);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Invert a route list. Used to support excluded routes on platforms that
|
||||||
|
// don't support them natively.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_ADDR_ROUTEINV_H
|
||||||
|
#define OPENVPN_ADDR_ROUTEINV_H
|
||||||
|
|
||||||
|
#include <openvpn/common/exception.hpp>
|
||||||
|
#include <openvpn/addr/route.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
namespace IP {
|
||||||
|
class RouteInverter : public RouteList
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OPENVPN_EXCEPTION(route_inverter);
|
||||||
|
|
||||||
|
RouteInverter() {}
|
||||||
|
|
||||||
|
// NOTE: when passing RouteInverter to this constructor, make sure
|
||||||
|
// to static_cast it to RouteList& so as to avoid matching the
|
||||||
|
// default copy constructor.
|
||||||
|
explicit RouteInverter(const RouteList& in)
|
||||||
|
: RouteInverter(in, in.version_mask())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
RouteInverter(const RouteList& in, const Addr::VersionMask vermask)
|
||||||
|
{
|
||||||
|
in.verify_canonical();
|
||||||
|
if (vermask & Addr::V4_MASK)
|
||||||
|
descend(in, Addr::V4, Route(Addr::from_zero(Addr::V4), 0));
|
||||||
|
if (vermask & Addr::V6_MASK)
|
||||||
|
descend(in, Addr::V6, Route(Addr::from_zero(Addr::V6), 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum Type {
|
||||||
|
EQUAL,
|
||||||
|
SUBROUTE,
|
||||||
|
LEAF,
|
||||||
|
};
|
||||||
|
|
||||||
|
void descend(const RouteList& in, const Addr::Version ver, const Route& route)
|
||||||
|
{
|
||||||
|
switch (find(in, route))
|
||||||
|
{
|
||||||
|
case SUBROUTE:
|
||||||
|
{
|
||||||
|
Route r1, r2;
|
||||||
|
if (route.split(r1, r2))
|
||||||
|
{
|
||||||
|
descend(in, ver, r1);
|
||||||
|
descend(in, ver, r2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
push_back(route);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case LEAF:
|
||||||
|
push_back(route);
|
||||||
|
break;
|
||||||
|
case EQUAL:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Type find(const RouteList& in, const Route& route)
|
||||||
|
{
|
||||||
|
Type type = LEAF;
|
||||||
|
for (RouteList::const_iterator i = in.begin(); i != in.end(); ++i)
|
||||||
|
{
|
||||||
|
const Route& r = *i;
|
||||||
|
if (route == r)
|
||||||
|
return EQUAL;
|
||||||
|
else if (route.contains(r))
|
||||||
|
type = SUBROUTE;
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,325 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_APPLE_MACLIFE_H
|
||||||
|
#define OPENVPN_APPLE_MACLIFE_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <openvpn/log/logthread.hpp>
|
||||||
|
#include <openvpn/applecrypto/cf/cftimer.hpp>
|
||||||
|
#include <openvpn/applecrypto/cf/cfhelper.hpp>
|
||||||
|
#include <openvpn/applecrypto/util/reachable.hpp>
|
||||||
|
#include <openvpn/client/clilife.hpp>
|
||||||
|
#include <openvpn/apple/runloop.hpp>
|
||||||
|
#include <openvpn/apple/macsleep.hpp>
|
||||||
|
#include <openvpn/apple/scdynstore.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
class MacLifeCycle : public ClientLifeCycle, MacSleep, ReachabilityTracker
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
OPENVPN_EXCEPTION(mac_lifecycle_error);
|
||||||
|
|
||||||
|
MacLifeCycle()
|
||||||
|
: ReachabilityTracker(true, false),
|
||||||
|
nc(nullptr),
|
||||||
|
thread(nullptr),
|
||||||
|
paused(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~MacLifeCycle()
|
||||||
|
{
|
||||||
|
stop_thread();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool network_available()
|
||||||
|
{
|
||||||
|
return net_up();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void start(NotifyCallback* nc_arg)
|
||||||
|
{
|
||||||
|
if (!thread && nc_arg)
|
||||||
|
{
|
||||||
|
nc = nc_arg;
|
||||||
|
thread = new std::thread(&MacLifeCycle::thread_func, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void stop()
|
||||||
|
{
|
||||||
|
stop_thread();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct State
|
||||||
|
{
|
||||||
|
State()
|
||||||
|
: net_up(false),
|
||||||
|
sleep(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
State(bool net_up_arg, const std::string& iface_arg, bool sleep_arg)
|
||||||
|
: net_up(net_up_arg),
|
||||||
|
iface(iface_arg),
|
||||||
|
sleep(sleep_arg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const State& other) const
|
||||||
|
{
|
||||||
|
return net_up == other.net_up && iface == other.iface && sleep == other.sleep;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const State& other) const
|
||||||
|
{
|
||||||
|
return !operator==(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string() const
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
os << "[net_up=" << net_up << " iface=" << iface << " sleep=" << sleep << ']';
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool net_up;
|
||||||
|
std::string iface;
|
||||||
|
bool sleep;
|
||||||
|
};
|
||||||
|
|
||||||
|
void stop_thread()
|
||||||
|
{
|
||||||
|
if (thread)
|
||||||
|
{
|
||||||
|
if (runloop.defined())
|
||||||
|
CFRunLoopStop(runloop());
|
||||||
|
thread->join();
|
||||||
|
delete thread;
|
||||||
|
thread = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void thread_func()
|
||||||
|
{
|
||||||
|
runloop.reset(CFRunLoopGetCurrent(), CF::BORROW);
|
||||||
|
Log::Context logctx(logwrap);
|
||||||
|
try {
|
||||||
|
// set up dynamic store query object
|
||||||
|
dstore.reset(SCDynamicStoreCreate(kCFAllocatorDefault,
|
||||||
|
CFSTR("OpenVPN_MacLifeCycle"),
|
||||||
|
nullptr,
|
||||||
|
nullptr));
|
||||||
|
|
||||||
|
// init state
|
||||||
|
state = State(net_up(), primary_interface(), false);
|
||||||
|
prev_state = state;
|
||||||
|
paused = false;
|
||||||
|
|
||||||
|
// enable sleep/wakeup notifications
|
||||||
|
mac_sleep_start();
|
||||||
|
|
||||||
|
// enable network reachability notifications
|
||||||
|
reachability_tracker_schedule();
|
||||||
|
|
||||||
|
// enable interface change notifications
|
||||||
|
iface_watch();
|
||||||
|
|
||||||
|
// process event loop until CFRunLoopStop is called from parent thread
|
||||||
|
CFRunLoopRun();
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
OPENVPN_LOG("MacLifeCycle Exception: " << e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
cancel_action_timer();
|
||||||
|
mac_sleep_stop();
|
||||||
|
reachability_tracker_cancel();
|
||||||
|
dstore.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string primary_interface()
|
||||||
|
{
|
||||||
|
CF::Dict dict(CF::DynamicStoreCopyDict(dstore, "State:/Network/Global/IPv4"));
|
||||||
|
return CF::dict_get_str(dict, "PrimaryInterface");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool net_up()
|
||||||
|
{
|
||||||
|
ReachabilityViaInternet r;
|
||||||
|
return ReachabilityViaInternet::status_from_flags(r.flags()) != ReachabilityInterface::NotReachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iface_watch()
|
||||||
|
{
|
||||||
|
SCDynamicStoreContext context = {0, this, nullptr, nullptr, nullptr};
|
||||||
|
CF::DynamicStore ds(SCDynamicStoreCreate(kCFAllocatorDefault,
|
||||||
|
CFSTR("OpenVPN_MacLifeCycle_iface_watch"),
|
||||||
|
iface_watch_callback_static,
|
||||||
|
&context));
|
||||||
|
if (!ds.defined())
|
||||||
|
throw mac_lifecycle_error("SCDynamicStoreCreate");
|
||||||
|
CF::MutableArray watched_keys(CF::mutable_array());
|
||||||
|
CF::array_append_str(watched_keys, "State:/Network/Global/IPv4");
|
||||||
|
//CF::array_append_str(watched_keys, "State:/Network/Global/IPv6");
|
||||||
|
if (!watched_keys.defined())
|
||||||
|
throw mac_lifecycle_error("watched_keys is undefined");
|
||||||
|
if (!SCDynamicStoreSetNotificationKeys(ds(),
|
||||||
|
watched_keys(),
|
||||||
|
nullptr))
|
||||||
|
throw mac_lifecycle_error("SCDynamicStoreSetNotificationKeys failed");
|
||||||
|
CF::RunLoopSource rls(SCDynamicStoreCreateRunLoopSource(kCFAllocatorDefault, ds(), 0));
|
||||||
|
if (!rls.defined())
|
||||||
|
throw mac_lifecycle_error("SCDynamicStoreCreateRunLoopSource failed");
|
||||||
|
CFRunLoopAddSource(CFRunLoopGetCurrent(), rls(), kCFRunLoopDefaultMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iface_watch_callback_static(SCDynamicStoreRef store, CFArrayRef changedKeys, void *arg)
|
||||||
|
{
|
||||||
|
MacLifeCycle *self = (MacLifeCycle *)arg;
|
||||||
|
self->iface_watch_callback(store, changedKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
void iface_watch_callback(SCDynamicStoreRef store, CFArrayRef changedKeys)
|
||||||
|
{
|
||||||
|
state.iface = primary_interface();
|
||||||
|
OPENVPN_LOG("MacLifeCycle NET_IFACE " << state.iface);
|
||||||
|
schedule_action_timer(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void notify_sleep()
|
||||||
|
{
|
||||||
|
OPENVPN_LOG("MacLifeCycle SLEEP");
|
||||||
|
state.sleep = true;
|
||||||
|
schedule_action_timer(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void notify_wakeup()
|
||||||
|
{
|
||||||
|
OPENVPN_LOG("MacLifeCycle WAKEUP");
|
||||||
|
state.sleep = false;
|
||||||
|
schedule_action_timer(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void reachability_tracker_event(const ReachabilityBase& rb, SCNetworkReachabilityFlags flags)
|
||||||
|
{
|
||||||
|
if (rb.vtype() == ReachabilityBase::Internet)
|
||||||
|
{
|
||||||
|
const ReachabilityBase::Status status = rb.vstatus(flags);
|
||||||
|
state.net_up = (status != ReachabilityInterface::NotReachable);
|
||||||
|
OPENVPN_LOG("MacLifeCycle NET_STATE " << state.net_up << " status=" << ReachabilityBase::render_status(status) << " flags=" << ReachabilityBase::render_flags(flags));
|
||||||
|
schedule_action_timer(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void schedule_action_timer(const int seconds)
|
||||||
|
{
|
||||||
|
cancel_action_timer();
|
||||||
|
if (seconds)
|
||||||
|
{
|
||||||
|
CFRunLoopTimerContext context = { 0, this, nullptr, nullptr, nullptr };
|
||||||
|
action_timer.reset(CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + seconds, 0, 0, 0, action_timer_callback_static, &context));
|
||||||
|
if (action_timer.defined())
|
||||||
|
CFRunLoopAddTimer(CFRunLoopGetCurrent(), action_timer(), kCFRunLoopCommonModes);
|
||||||
|
else
|
||||||
|
OPENVPN_LOG("MacLifeCycle::schedule_action_timer: failed to create timer");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
action_timer_callback(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cancel_action_timer()
|
||||||
|
{
|
||||||
|
if (action_timer.defined())
|
||||||
|
{
|
||||||
|
CFRunLoopTimerInvalidate(action_timer());
|
||||||
|
action_timer.reset(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void action_timer_callback_static(CFRunLoopTimerRef timer, void *info)
|
||||||
|
{
|
||||||
|
MacLifeCycle* self = (MacLifeCycle*)info;
|
||||||
|
self->action_timer_callback(timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void action_timer_callback(CFRunLoopTimerRef timer)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (state != prev_state)
|
||||||
|
{
|
||||||
|
OPENVPN_LOG("MacLifeCycle ACTION pause=" << paused << " state=" << state.to_string() << " prev=" << prev_state.to_string());
|
||||||
|
if (paused)
|
||||||
|
{
|
||||||
|
if (!state.sleep && state.net_up)
|
||||||
|
{
|
||||||
|
nc->cln_resume();
|
||||||
|
paused = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (state.sleep)
|
||||||
|
{
|
||||||
|
nc->cln_pause("sleep");
|
||||||
|
paused = true;
|
||||||
|
}
|
||||||
|
else if (!state.net_up)
|
||||||
|
{
|
||||||
|
nc->cln_pause("network-unavailable");
|
||||||
|
paused = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (state.iface != prev_state.iface)
|
||||||
|
nc->cln_reconnect(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prev_state = state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (const std::exception& e)
|
||||||
|
{
|
||||||
|
OPENVPN_LOG("MacLifeCycle::action_timer_callback: " << e.what());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NotifyCallback* nc;
|
||||||
|
std::thread* thread;
|
||||||
|
CF::RunLoop runloop; // run loop in thread
|
||||||
|
CF::DynamicStore dstore;
|
||||||
|
State state;
|
||||||
|
State prev_state;
|
||||||
|
bool paused;
|
||||||
|
CF::Timer action_timer;
|
||||||
|
Log::Context::Wrapper logwrap; // used to carry forward the log context from parent thread
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_APPLE_MACSLEEP_H
|
||||||
|
#define OPENVPN_APPLE_MACSLEEP_H
|
||||||
|
|
||||||
|
#include <mach/mach_port.h>
|
||||||
|
#include <mach/mach_interface.h>
|
||||||
|
#include <mach/mach_init.h>
|
||||||
|
|
||||||
|
#include <IOKit/pwr_mgt/IOPMLib.h>
|
||||||
|
#include <IOKit/IOMessage.h>
|
||||||
|
|
||||||
|
#include <openvpn/common/size.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
class MacSleep
|
||||||
|
{
|
||||||
|
MacSleep(const MacSleep&) = delete;
|
||||||
|
MacSleep& operator=(const MacSleep&) = delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
MacSleep()
|
||||||
|
: root_port(0),
|
||||||
|
notifyPortRef(nullptr),
|
||||||
|
notifierObject(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~MacSleep()
|
||||||
|
{
|
||||||
|
mac_sleep_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mac_sleep_start()
|
||||||
|
{
|
||||||
|
if (!root_port)
|
||||||
|
{
|
||||||
|
root_port = IORegisterForSystemPower(this, ¬ifyPortRef, callback_static, ¬ifierObject);
|
||||||
|
if (!root_port)
|
||||||
|
return false;
|
||||||
|
CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notifyPortRef), kCFRunLoopCommonModes);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void mac_sleep_stop()
|
||||||
|
{
|
||||||
|
if (root_port)
|
||||||
|
{
|
||||||
|
// remove the sleep notification port from the application runloop
|
||||||
|
CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
|
||||||
|
IONotificationPortGetRunLoopSource(notifyPortRef),
|
||||||
|
kCFRunLoopCommonModes);
|
||||||
|
|
||||||
|
// deregister for system sleep notifications
|
||||||
|
IODeregisterForSystemPower(¬ifierObject);
|
||||||
|
|
||||||
|
// IORegisterForSystemPower implicitly opens the Root Power Domain IOService
|
||||||
|
// so we close it here
|
||||||
|
IOServiceClose(root_port);
|
||||||
|
|
||||||
|
// destroy the notification port allocated by IORegisterForSystemPower
|
||||||
|
IONotificationPortDestroy(notifyPortRef);
|
||||||
|
|
||||||
|
// reset object members
|
||||||
|
root_port = 0;
|
||||||
|
notifyPortRef = nullptr;
|
||||||
|
notifierObject = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void notify_sleep() = 0;
|
||||||
|
virtual void notify_wakeup() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void callback_static(void* arg, io_service_t service, natural_t messageType, void *messageArgument)
|
||||||
|
{
|
||||||
|
MacSleep* self = (MacSleep*)arg;
|
||||||
|
self->callback(service, messageType, messageArgument);
|
||||||
|
}
|
||||||
|
|
||||||
|
void callback(io_service_t service, natural_t messageType, void *messageArgument)
|
||||||
|
{
|
||||||
|
switch (messageType)
|
||||||
|
{
|
||||||
|
case kIOMessageCanSystemSleep:
|
||||||
|
IOAllowPowerChange(root_port, (long)messageArgument);
|
||||||
|
break;
|
||||||
|
case kIOMessageSystemWillSleep:
|
||||||
|
notify_sleep();
|
||||||
|
IOAllowPowerChange(root_port, (long)messageArgument);
|
||||||
|
break;
|
||||||
|
case kIOMessageSystemHasPoweredOn:
|
||||||
|
notify_wakeup();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// a reference to the Root Power Domain IOService
|
||||||
|
io_connect_t root_port;
|
||||||
|
|
||||||
|
// notification port allocated by IORegisterForSystemPower
|
||||||
|
IONotificationPortRef notifyPortRef;
|
||||||
|
|
||||||
|
// notifier object, used to deregister later
|
||||||
|
io_object_t notifierObject;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_APPLE_MACVER_H
|
||||||
|
#define OPENVPN_APPLE_MACVER_H
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <openvpn/common/split.hpp>
|
||||||
|
#include <openvpn/common/number.hpp>
|
||||||
|
#include <openvpn/apple/ver.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
namespace Mac {
|
||||||
|
class Version : public AppleVersion
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Mac OS X versions
|
||||||
|
// 15.x.x OS X 10.11.x El Capitan
|
||||||
|
// 14.x.x OS X 10.10.x Yosemite
|
||||||
|
// 13.x.x OS X 10.9.x Mavericks
|
||||||
|
// 12.x.x OS X 10.8.x Mountain Lion
|
||||||
|
// 11.x.x OS X 10.7.x Lion
|
||||||
|
// 10.x.x OS X 10.6.x Snow Leopard
|
||||||
|
// 9.x.x OS X 10.5.x Leopard
|
||||||
|
// 8.x.x OS X 10.4.x Tiger
|
||||||
|
// 7.x.x OS X 10.3.x Panther
|
||||||
|
// 6.x.x OS X 10.2.x Jaguar
|
||||||
|
// 5.x OS X 10.1.x Puma
|
||||||
|
|
||||||
|
enum {
|
||||||
|
OSX_10_11=15,
|
||||||
|
OSX_10_10=14,
|
||||||
|
OSX_10_9=13,
|
||||||
|
OSX_10_8=12,
|
||||||
|
OSX_10_7=11,
|
||||||
|
OSX_10_6=10,
|
||||||
|
};
|
||||||
|
|
||||||
|
Version()
|
||||||
|
{
|
||||||
|
char str[256];
|
||||||
|
size_t size = sizeof(str);
|
||||||
|
int ret = sysctlbyname("kern.osrelease", str, &size, nullptr, 0);
|
||||||
|
if (!ret)
|
||||||
|
init(std::string(str, size));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_APPLE_RUNLOOP_H
|
||||||
|
#define OPENVPN_APPLE_RUNLOOP_H
|
||||||
|
|
||||||
|
#include <openvpn/applecrypto/cf/cf.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
namespace CF {
|
||||||
|
OPENVPN_CF_WRAP(RunLoop, runloop_cast, CFRunLoopRef, CFRunLoopGetTypeID);
|
||||||
|
OPENVPN_CF_WRAP(RunLoopSource, runloop_source_cast, CFRunLoopSourceRef, CFRunLoopSourceGetTypeID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_APPLE_SCDYNSTORE_H
|
||||||
|
#define OPENVPN_APPLE_SCDYNSTORE_H
|
||||||
|
|
||||||
|
#include <SystemConfiguration/SCDynamicStore.h>
|
||||||
|
|
||||||
|
#include <openvpn/applecrypto/cf/cf.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
namespace CF {
|
||||||
|
OPENVPN_CF_WRAP(DynamicStore, dynamic_store_cast, SCDynamicStoreRef, SCDynamicStoreGetTypeID)
|
||||||
|
|
||||||
|
template <typename RET, typename KEY>
|
||||||
|
inline RET DynamicStoreCopy(const DynamicStore& ds, const KEY& key)
|
||||||
|
{
|
||||||
|
String keystr = string(key);
|
||||||
|
return RET(RET::cast(SCDynamicStoreCopyValue(ds(), keystr())));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename KEY>
|
||||||
|
inline Dict DynamicStoreCopyDict(const DynamicStore& ds, const KEY& key)
|
||||||
|
{
|
||||||
|
Dict dict = DynamicStoreCopy<Dict>(ds, key);
|
||||||
|
if (dict.defined())
|
||||||
|
return dict;
|
||||||
|
else
|
||||||
|
return CF::empty_dict();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_APPLE_VER_H
|
||||||
|
#define OPENVPN_APPLE_VER_H
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <sys/sysctl.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <openvpn/common/split.hpp>
|
||||||
|
#include <openvpn/common/number.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
class AppleVersion
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int major() const { return ver[0]; }
|
||||||
|
int minor() const { return ver[1]; }
|
||||||
|
int build() const { return ver[2]; }
|
||||||
|
|
||||||
|
std::string to_string() const
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
os << major() << '.' << minor() << '.' << build();
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
AppleVersion()
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
// verstr should be in the form major.minor.build
|
||||||
|
void init(const std::string& verstr)
|
||||||
|
{
|
||||||
|
typedef std::vector<std::string> StringList;
|
||||||
|
reset();
|
||||||
|
StringList sl;
|
||||||
|
sl.reserve(3);
|
||||||
|
Split::by_char_void<StringList, NullLex, Split::NullLimit>(sl, verstr, '.');
|
||||||
|
for (size_t i = 0; i < 3; ++i)
|
||||||
|
{
|
||||||
|
if (i < sl.size())
|
||||||
|
parse_number(sl[i], ver[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void reset()
|
||||||
|
{
|
||||||
|
ver[0] = ver[1] = ver[2] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ver[3];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,464 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_APPLECRYPTO_CF_CF_H
|
||||||
|
#define OPENVPN_APPLECRYPTO_CF_CF_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
|
||||||
|
#include <openvpn/common/size.hpp>
|
||||||
|
#include <openvpn/common/exception.hpp>
|
||||||
|
#include <openvpn/buffer/buffer.hpp>
|
||||||
|
|
||||||
|
// Wrapper classes for Apple Core Foundation objects.
|
||||||
|
|
||||||
|
#define OPENVPN_CF_WRAP(cls, castmeth, cftype, idmeth) \
|
||||||
|
template <> \
|
||||||
|
struct Type<cftype> \
|
||||||
|
{ \
|
||||||
|
static CFTypeRef cast(CFTypeRef obj) \
|
||||||
|
{ \
|
||||||
|
if (obj && CFGetTypeID(obj) == idmeth()) \
|
||||||
|
return obj; \
|
||||||
|
else \
|
||||||
|
return nullptr; \
|
||||||
|
} \
|
||||||
|
}; \
|
||||||
|
typedef Wrap<cftype> cls; \
|
||||||
|
inline cls castmeth(CFTypeRef obj) \
|
||||||
|
{ \
|
||||||
|
CFTypeRef o = Type<cftype>::cast(obj); \
|
||||||
|
if (o) \
|
||||||
|
return cls(cftype(o), BORROW); \
|
||||||
|
else \
|
||||||
|
return cls(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
namespace CF
|
||||||
|
{
|
||||||
|
enum Own {
|
||||||
|
OWN,
|
||||||
|
BORROW
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> struct Type {};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class Wrap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Wrap() : obj_(nullptr) {}
|
||||||
|
|
||||||
|
// Set own=BORROW if we don't currently own the object
|
||||||
|
explicit Wrap(T obj, const Own own=OWN)
|
||||||
|
{
|
||||||
|
if (own == BORROW && obj)
|
||||||
|
CFRetain(obj);
|
||||||
|
obj_ = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
Wrap(const Wrap& other)
|
||||||
|
{
|
||||||
|
obj_ = other.obj_;
|
||||||
|
if (obj_)
|
||||||
|
CFRetain(obj_);
|
||||||
|
}
|
||||||
|
|
||||||
|
Wrap& operator=(const Wrap& other)
|
||||||
|
{
|
||||||
|
if (other.obj_)
|
||||||
|
CFRetain(other.obj_);
|
||||||
|
if (obj_)
|
||||||
|
CFRelease(obj_);
|
||||||
|
obj_ = other.obj_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Wrap(Wrap&& other) noexcept
|
||||||
|
{
|
||||||
|
obj_ = other.obj_;
|
||||||
|
other.obj_ = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Wrap& operator=(Wrap&& other) noexcept
|
||||||
|
{
|
||||||
|
if (obj_)
|
||||||
|
CFRelease(obj_);
|
||||||
|
obj_ = other.obj_;
|
||||||
|
other.obj_ = nullptr;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(Wrap& other)
|
||||||
|
{
|
||||||
|
std::swap(obj_, other.obj_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset(T obj=nullptr, const Own own=OWN)
|
||||||
|
{
|
||||||
|
if (own == BORROW && obj)
|
||||||
|
CFRetain(obj);
|
||||||
|
if (obj_)
|
||||||
|
CFRelease(obj_);
|
||||||
|
obj_ = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool defined() const { return obj_ != nullptr; }
|
||||||
|
|
||||||
|
T operator()() const { return obj_; }
|
||||||
|
|
||||||
|
CFTypeRef generic() const { return (CFTypeRef)obj_; }
|
||||||
|
|
||||||
|
static T cast(CFTypeRef obj) { return T(Type<T>::cast(obj)); }
|
||||||
|
|
||||||
|
static Wrap from_generic(CFTypeRef obj, const Own own=OWN)
|
||||||
|
{
|
||||||
|
return Wrap(cast(obj), own);
|
||||||
|
}
|
||||||
|
|
||||||
|
T release()
|
||||||
|
{
|
||||||
|
T ret = obj_;
|
||||||
|
obj_ = nullptr;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFTypeRef generic_release()
|
||||||
|
{
|
||||||
|
T ret = obj_;
|
||||||
|
obj_ = nullptr;
|
||||||
|
return (CFTypeRef)ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intended for use with Core Foundation methods that require
|
||||||
|
// a T* for saving a (non-borrowed) return value
|
||||||
|
T* mod_ref()
|
||||||
|
{
|
||||||
|
if (obj_)
|
||||||
|
{
|
||||||
|
CFRelease(obj_);
|
||||||
|
obj_ = nullptr;
|
||||||
|
}
|
||||||
|
return &obj_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void show() const
|
||||||
|
{
|
||||||
|
if (obj_)
|
||||||
|
CFShow(obj_);
|
||||||
|
else
|
||||||
|
std::cerr << "CF_UNDEFINED" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~Wrap()
|
||||||
|
{
|
||||||
|
if (obj_)
|
||||||
|
CFRelease(obj_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Wrap& operator=(T obj); // prevent use because no way to pass ownership parameter
|
||||||
|
|
||||||
|
T obj_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// essentially a vector of void *, used as source for array and dictionary constructors
|
||||||
|
typedef BufferAllocatedType<CFTypeRef> SrcList;
|
||||||
|
|
||||||
|
// common CF types
|
||||||
|
|
||||||
|
OPENVPN_CF_WRAP(String, string_cast, CFStringRef, CFStringGetTypeID)
|
||||||
|
OPENVPN_CF_WRAP(Number, number_cast, CFNumberRef, CFNumberGetTypeID)
|
||||||
|
OPENVPN_CF_WRAP(Bool, bool_cast, CFBooleanRef, CFBooleanGetTypeID)
|
||||||
|
OPENVPN_CF_WRAP(Data, data_cast, CFDataRef, CFDataGetTypeID)
|
||||||
|
OPENVPN_CF_WRAP(Array, array_cast, CFArrayRef, CFArrayGetTypeID)
|
||||||
|
OPENVPN_CF_WRAP(MutableArray, mutable_array_cast, CFMutableArrayRef, CFArrayGetTypeID)
|
||||||
|
OPENVPN_CF_WRAP(Dict, dict_cast, CFDictionaryRef, CFDictionaryGetTypeID)
|
||||||
|
OPENVPN_CF_WRAP(MutableDict, mutable_dict_cast, CFMutableDictionaryRef, CFDictionaryGetTypeID)
|
||||||
|
OPENVPN_CF_WRAP(Error, error_cast, CFErrorRef, CFErrorGetTypeID);
|
||||||
|
|
||||||
|
// generic CFTypeRef wrapper
|
||||||
|
|
||||||
|
typedef Wrap<CFTypeRef> Generic;
|
||||||
|
|
||||||
|
inline Generic generic_cast(CFTypeRef obj)
|
||||||
|
{
|
||||||
|
return Generic(obj, BORROW);
|
||||||
|
}
|
||||||
|
|
||||||
|
// constructors
|
||||||
|
|
||||||
|
inline String string(const char *str)
|
||||||
|
{
|
||||||
|
return String(CFStringCreateWithCString(kCFAllocatorDefault, str, kCFStringEncodingUTF8));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline String string(CFStringRef str)
|
||||||
|
{
|
||||||
|
return String(str, BORROW);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline String string(const String& str)
|
||||||
|
{
|
||||||
|
return String(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline String string(const std::string& str)
|
||||||
|
{
|
||||||
|
return String(CFStringCreateWithCString(kCFAllocatorDefault, str.c_str(), kCFStringEncodingUTF8));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline String string(const std::string* str)
|
||||||
|
{
|
||||||
|
return String(CFStringCreateWithCString(kCFAllocatorDefault, str->c_str(), kCFStringEncodingUTF8));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Number number_from_int(const int n)
|
||||||
|
{
|
||||||
|
return Number(CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &n));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Number number_from_int32(const SInt32 n)
|
||||||
|
{
|
||||||
|
return Number(CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &n));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Number number_from_long_long(const long long n)
|
||||||
|
{
|
||||||
|
return Number(CFNumberCreate(kCFAllocatorDefault, kCFNumberLongLongType, &n));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Number number_from_index(const CFIndex n)
|
||||||
|
{
|
||||||
|
return Number(CFNumberCreate(kCFAllocatorDefault, kCFNumberCFIndexType, &n));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Data data(const void *bytes, CFIndex length)
|
||||||
|
{
|
||||||
|
return Data(CFDataCreate(kCFAllocatorDefault, (const UInt8 *)bytes, length));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Array array(const void **values, CFIndex numValues)
|
||||||
|
{
|
||||||
|
return Array(CFArrayCreate(kCFAllocatorDefault, values, numValues, &kCFTypeArrayCallBacks));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Array array(const SrcList& values)
|
||||||
|
{
|
||||||
|
return array((const void **)values.c_data(), values.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Dict dict(const void **keys, const void **values, CFIndex numValues)
|
||||||
|
{
|
||||||
|
return Dict(CFDictionaryCreate(kCFAllocatorDefault,
|
||||||
|
keys,
|
||||||
|
values,
|
||||||
|
numValues,
|
||||||
|
&kCFTypeDictionaryKeyCallBacks,
|
||||||
|
&kCFTypeDictionaryValueCallBacks));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Dict dict(const SrcList& keys, const SrcList& values)
|
||||||
|
{
|
||||||
|
return dict((const void **)keys.c_data(), (const void **)values.c_data(), std::min(keys.size(), values.size()));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Dict const_dict(MutableDict& mdict)
|
||||||
|
{
|
||||||
|
return Dict(mdict(), CF::BORROW);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Array const_array(MutableArray& marray)
|
||||||
|
{
|
||||||
|
return Array(marray(), CF::BORROW);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Dict empty_dict()
|
||||||
|
{
|
||||||
|
return Dict(CFDictionaryCreate(kCFAllocatorDefault,
|
||||||
|
nullptr,
|
||||||
|
nullptr,
|
||||||
|
0,
|
||||||
|
&kCFTypeDictionaryKeyCallBacks,
|
||||||
|
&kCFTypeDictionaryValueCallBacks));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline MutableArray mutable_array(const CFIndex capacity=0)
|
||||||
|
{
|
||||||
|
return MutableArray(CFArrayCreateMutable(kCFAllocatorDefault, capacity, &kCFTypeArrayCallBacks));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline MutableDict mutable_dict(const CFIndex capacity=0)
|
||||||
|
{
|
||||||
|
return MutableDict(CFDictionaryCreateMutable(kCFAllocatorDefault, capacity, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename DICT>
|
||||||
|
inline MutableDict mutable_dict_copy(const DICT& dict, const CFIndex capacity=0)
|
||||||
|
{
|
||||||
|
if (dict.defined())
|
||||||
|
return MutableDict(CFDictionaryCreateMutableCopy(kCFAllocatorDefault, capacity, dict()));
|
||||||
|
else
|
||||||
|
return mutable_dict(capacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Error error(CFStringRef domain, CFIndex code, CFDictionaryRef userInfo)
|
||||||
|
{
|
||||||
|
return Error(CFErrorCreate(kCFAllocatorDefault, domain, code, userInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
// accessors
|
||||||
|
|
||||||
|
template <typename ARRAY>
|
||||||
|
inline CFIndex array_len(const ARRAY& array)
|
||||||
|
{
|
||||||
|
if (array.defined())
|
||||||
|
return CFArrayGetCount(array());
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename DICT>
|
||||||
|
inline CFIndex dict_len(const DICT& dict)
|
||||||
|
{
|
||||||
|
if (dict.defined())
|
||||||
|
return CFDictionaryGetCount(dict());
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename ARRAY>
|
||||||
|
inline CFTypeRef array_index(const ARRAY& array, const CFIndex idx)
|
||||||
|
{
|
||||||
|
if (array.defined() && CFArrayGetCount(array()) > idx)
|
||||||
|
return CFArrayGetValueAtIndex(array(), idx);
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename DICT, typename KEY>
|
||||||
|
inline CFTypeRef dict_index(const DICT& dict, const KEY& key)
|
||||||
|
{
|
||||||
|
if (dict.defined())
|
||||||
|
{
|
||||||
|
String keystr = string(key);
|
||||||
|
if (keystr.defined())
|
||||||
|
return CFDictionaryGetValue(dict(), keystr());
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// string methods
|
||||||
|
|
||||||
|
OPENVPN_SIMPLE_EXCEPTION(cppstring_error);
|
||||||
|
|
||||||
|
inline std::string cppstring(CFStringRef str)
|
||||||
|
{
|
||||||
|
const CFStringEncoding encoding = kCFStringEncodingUTF8;
|
||||||
|
if (str)
|
||||||
|
{
|
||||||
|
const CFIndex len = CFStringGetLength(str);
|
||||||
|
if (len > 0)
|
||||||
|
{
|
||||||
|
const CFIndex maxsize = CFStringGetMaximumSizeForEncoding(len, encoding);
|
||||||
|
char *buf = new char[maxsize];
|
||||||
|
const Boolean status = CFStringGetCString(str, buf, maxsize, encoding);
|
||||||
|
if (status)
|
||||||
|
{
|
||||||
|
std::string ret(buf);
|
||||||
|
delete [] buf;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delete [] buf;
|
||||||
|
throw cppstring_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string cppstring(const String& str)
|
||||||
|
{
|
||||||
|
return cppstring(str());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string description(CFTypeRef obj)
|
||||||
|
{
|
||||||
|
if (obj)
|
||||||
|
{
|
||||||
|
String s(CFCopyDescription(obj));
|
||||||
|
return cppstring(s);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return "UNDEF";
|
||||||
|
}
|
||||||
|
|
||||||
|
// format an array of strings (non-string elements in array are ignored)
|
||||||
|
template <typename ARRAY>
|
||||||
|
inline std::string array_to_string(const ARRAY& array, const char delim=',')
|
||||||
|
{
|
||||||
|
std::ostringstream os;
|
||||||
|
const CFIndex len = array_len(array);
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
bool sep = false;
|
||||||
|
for (CFIndex i = 0; i < len; ++i)
|
||||||
|
{
|
||||||
|
const String v(string_cast(array_index(array, i)));
|
||||||
|
if (v.defined())
|
||||||
|
{
|
||||||
|
if (sep)
|
||||||
|
os << delim;
|
||||||
|
os << cppstring(v);
|
||||||
|
sep = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return os.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool string_equal(const String& s1, const String& s2, const CFStringCompareFlags compareOptions = 0)
|
||||||
|
{
|
||||||
|
return s1.defined() && s2.defined() && CFStringCompare(s1(), s2(), compareOptions) == kCFCompareEqualTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
// property lists
|
||||||
|
inline Data plist(CFTypeRef obj)
|
||||||
|
{
|
||||||
|
return Data(CFPropertyListCreateData(kCFAllocatorDefault,
|
||||||
|
obj,
|
||||||
|
kCFPropertyListBinaryFormat_v1_0,
|
||||||
|
0,
|
||||||
|
nullptr));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace CF
|
||||||
|
} // namespace openvpn
|
||||||
|
|
||||||
|
#endif // OPENVPN_APPLECRYPTO_CF_CF_H
|
||||||
@@ -0,0 +1,247 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_APPLECRYPTO_CF_CFHELPER_H
|
||||||
|
#define OPENVPN_APPLECRYPTO_CF_CFHELPER_H
|
||||||
|
|
||||||
|
#include <openvpn/applecrypto/cf/cf.hpp>
|
||||||
|
|
||||||
|
// These methods build on the Wrapper classes for Apple Core Foundation objects
|
||||||
|
// defined in cf.hpp. They add additional convenience methods, such as dictionary
|
||||||
|
// lookup.
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
namespace CF {
|
||||||
|
|
||||||
|
inline CFTypeRef mutable_dict_new()
|
||||||
|
{
|
||||||
|
return CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline CFTypeRef mutable_array_new()
|
||||||
|
{
|
||||||
|
return CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lookup or create (if absent) an item in a mutable dictionary.
|
||||||
|
// Return the item, which will be owned by base.
|
||||||
|
template <typename KEY>
|
||||||
|
inline CFTypeRef dict_get_create(CFMutableDictionaryRef base,
|
||||||
|
const KEY& key,
|
||||||
|
CFTypeRef (*create_method)())
|
||||||
|
{
|
||||||
|
if (base)
|
||||||
|
{
|
||||||
|
String keystr = string(key);
|
||||||
|
CFTypeRef ret = CFDictionaryGetValue(base, keystr()); // try lookup first
|
||||||
|
if (!ret)
|
||||||
|
{
|
||||||
|
// doesn't exist, must create
|
||||||
|
ret = (*create_method)();
|
||||||
|
CFDictionaryAddValue(base, keystr(), ret);
|
||||||
|
CFRelease(ret); // because ret is now owned by base
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// lookup a dict in another dict (base) and return or create if absent
|
||||||
|
template <typename KEY>
|
||||||
|
inline MutableDict dict_get_create_dict(MutableDict& base, const KEY& key)
|
||||||
|
{
|
||||||
|
String keystr = string(key);
|
||||||
|
return mutable_dict_cast(dict_get_create(base(), keystr(), mutable_dict_new));
|
||||||
|
}
|
||||||
|
|
||||||
|
// lookup an array in a dict (base) and return or create if absent
|
||||||
|
template <typename KEY>
|
||||||
|
inline MutableArray dict_get_create_array(MutableDict& base, const KEY& key)
|
||||||
|
{
|
||||||
|
String keystr = string(key);
|
||||||
|
return mutable_array_cast(dict_get_create(base(), keystr(), mutable_array_new));
|
||||||
|
}
|
||||||
|
|
||||||
|
// lookup an object in a dictionary (DICT should be a Dict or a MutableDict)
|
||||||
|
template <typename DICT, typename KEY>
|
||||||
|
inline CFTypeRef dict_get_obj(const DICT& dict, const KEY& key)
|
||||||
|
{
|
||||||
|
return dict_index(dict, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// lookup a string in a dictionary (DICT should be a Dict or a MutableDict)
|
||||||
|
template <typename DICT, typename KEY>
|
||||||
|
inline std::string dict_get_str(const DICT& dict, const KEY& key)
|
||||||
|
{
|
||||||
|
return cppstring(string_cast(dict_index(dict, key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// lookup a string in a dictionary (DICT should be a Dict or a MutableDict)
|
||||||
|
template <typename DICT, typename KEY>
|
||||||
|
inline std::string dict_get_str(const DICT& dict, const KEY& key, const std::string& default_value)
|
||||||
|
{
|
||||||
|
String str(string_cast(dict_index(dict, key)));
|
||||||
|
if (str.defined())
|
||||||
|
return cppstring(str());
|
||||||
|
else
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// lookup an integer in a dictionary (DICT should be a Dict or a MutableDict)
|
||||||
|
template <typename DICT, typename KEY>
|
||||||
|
inline int dict_get_int(const DICT& dict, const KEY& key, const int default_value)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
Number num = number_cast(dict_index(dict, key));
|
||||||
|
if (num.defined() && CFNumberGetValue(num(), kCFNumberIntType, &ret))
|
||||||
|
return ret;
|
||||||
|
else
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// lookup a boolean in a dictionary (DICT should be a Dict or a MutableDict)
|
||||||
|
template <typename DICT, typename KEY>
|
||||||
|
inline bool dict_get_bool(const DICT& dict, const KEY& key, const bool default_value)
|
||||||
|
{
|
||||||
|
Bool b = bool_cast(dict_index(dict, key));
|
||||||
|
if (b.defined())
|
||||||
|
{
|
||||||
|
if (b() == kCFBooleanTrue)
|
||||||
|
return true;
|
||||||
|
else if (b() == kCFBooleanFalse)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return default_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// like CFDictionarySetValue, but no-op if any args are NULL
|
||||||
|
inline void dictionarySetValue(CFMutableDictionaryRef theDict, const void *key, const void *value)
|
||||||
|
{
|
||||||
|
if (theDict && key && value)
|
||||||
|
CFDictionarySetValue(theDict, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// like CFArrayAppendValue, but no-op if any args are NULL
|
||||||
|
inline void arrayAppendValue(CFMutableArrayRef theArray, const void *value)
|
||||||
|
{
|
||||||
|
if (theArray && value)
|
||||||
|
CFArrayAppendValue(theArray, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set a CFTypeRef in a mutable dictionary
|
||||||
|
template <typename KEY>
|
||||||
|
inline void dict_set_obj(MutableDict& dict, const KEY& key, CFTypeRef value)
|
||||||
|
{
|
||||||
|
String keystr = string(key);
|
||||||
|
dictionarySetValue(dict(), keystr(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// set a string in a mutable dictionary
|
||||||
|
|
||||||
|
template <typename KEY, typename VALUE>
|
||||||
|
inline void dict_set_str(MutableDict& dict, const KEY& key, const VALUE& value)
|
||||||
|
{
|
||||||
|
String keystr = string(key);
|
||||||
|
String valstr = string(value);
|
||||||
|
dictionarySetValue(dict(), keystr(), valstr());
|
||||||
|
}
|
||||||
|
|
||||||
|
// set a number in a mutable dictionary
|
||||||
|
|
||||||
|
template <typename KEY>
|
||||||
|
inline void dict_set_int(MutableDict& dict, const KEY& key, int value)
|
||||||
|
{
|
||||||
|
String keystr = string(key);
|
||||||
|
Number num = number_from_int(value);
|
||||||
|
dictionarySetValue(dict(), keystr(), num());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename KEY>
|
||||||
|
inline void dict_set_int32(MutableDict& dict, const KEY& key, SInt32 value)
|
||||||
|
{
|
||||||
|
String keystr = string(key);
|
||||||
|
Number num = number_from_int32(value);
|
||||||
|
dictionarySetValue(dict(), keystr(), num());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename KEY>
|
||||||
|
inline void dict_set_long_long(MutableDict& dict, const KEY& key, long long value)
|
||||||
|
{
|
||||||
|
String keystr = string(key);
|
||||||
|
Number num = number_from_long_long(value);
|
||||||
|
dictionarySetValue(dict(), keystr(), num());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename KEY>
|
||||||
|
inline void dict_set_index(MutableDict& dict, const KEY& key, CFIndex value)
|
||||||
|
{
|
||||||
|
String keystr = string(key);
|
||||||
|
Number num = number_from_index(value);
|
||||||
|
dictionarySetValue((CFMutableDictionaryRef)dict(), keystr(), num());
|
||||||
|
}
|
||||||
|
|
||||||
|
// set a boolean in a mutable dictionary
|
||||||
|
|
||||||
|
template <typename KEY>
|
||||||
|
inline void dict_set_bool(MutableDict& dict, const KEY& key, bool value)
|
||||||
|
{
|
||||||
|
String keystr = string(key);
|
||||||
|
CFBooleanRef boolref = value ? kCFBooleanTrue : kCFBooleanFalse;
|
||||||
|
dictionarySetValue(dict(), keystr(), boolref);
|
||||||
|
}
|
||||||
|
|
||||||
|
// append string to a mutable array
|
||||||
|
|
||||||
|
template <typename VALUE>
|
||||||
|
inline void array_append_str(MutableArray& array, const VALUE& value)
|
||||||
|
{
|
||||||
|
String valstr = string(value);
|
||||||
|
arrayAppendValue(array(), valstr());
|
||||||
|
}
|
||||||
|
|
||||||
|
// append a number to a mutable array
|
||||||
|
|
||||||
|
inline void array_append_int(MutableArray& array, int value)
|
||||||
|
{
|
||||||
|
Number num = number_from_int(value);
|
||||||
|
arrayAppendValue(array(), num());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void array_append_int32(MutableArray& array, SInt32 value)
|
||||||
|
{
|
||||||
|
Number num = number_from_int32(value);
|
||||||
|
arrayAppendValue(array(), num());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void array_append_long_long(MutableArray& array, long long value)
|
||||||
|
{
|
||||||
|
Number num = number_from_long_long(value);
|
||||||
|
arrayAppendValue(array(), num());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void array_append_index(MutableArray& array, CFIndex value)
|
||||||
|
{
|
||||||
|
Number num = number_from_index(value);
|
||||||
|
arrayAppendValue(array(), num());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_APPLECRYPTO_CF_CFSEC_H
|
||||||
|
#define OPENVPN_APPLECRYPTO_CF_CFSEC_H
|
||||||
|
|
||||||
|
#include <openvpn/common/platform.hpp>
|
||||||
|
|
||||||
|
#include <Security/SecCertificate.h>
|
||||||
|
#include <Security/SecIdentity.h>
|
||||||
|
#include <Security/SecPolicy.h>
|
||||||
|
#include <Security/SecTrust.h>
|
||||||
|
|
||||||
|
#ifndef OPENVPN_PLATFORM_IPHONE
|
||||||
|
#include <Security/SecKeychain.h>
|
||||||
|
#include <Security/SecAccess.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <openvpn/common/size.hpp>
|
||||||
|
#include <openvpn/common/exception.hpp>
|
||||||
|
#include <openvpn/applecrypto/cf/cf.hpp>
|
||||||
|
|
||||||
|
// Define C++ wrappings for Apple security-related objects.
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
namespace CF {
|
||||||
|
OPENVPN_CF_WRAP(Cert, cert_cast, SecCertificateRef, SecCertificateGetTypeID)
|
||||||
|
OPENVPN_CF_WRAP(Key, key_cast, SecKeyRef, SecKeyGetTypeID)
|
||||||
|
OPENVPN_CF_WRAP(Identity, identity_cast, SecIdentityRef, SecIdentityGetTypeID)
|
||||||
|
OPENVPN_CF_WRAP(Policy, policy_cast, SecPolicyRef, SecPolicyGetTypeID)
|
||||||
|
OPENVPN_CF_WRAP(Trust, trust_cast, SecTrustRef, SecTrustGetTypeID)
|
||||||
|
#ifndef OPENVPN_PLATFORM_IPHONE
|
||||||
|
OPENVPN_CF_WRAP(Keychain, keychain_cast, SecKeychainRef, SecKeychainGetTypeID)
|
||||||
|
OPENVPN_CF_WRAP(Access, access_cast, SecAccessRef, SecAccessGetTypeID)
|
||||||
|
#endif
|
||||||
|
} // namespace CF
|
||||||
|
|
||||||
|
} // namespace openvpn
|
||||||
|
|
||||||
|
#endif // OPENVPN_APPLECRYPTO_CF_CFSEC_H
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_APPLECRYPTO_CF_CFTIMER_H
|
||||||
|
#define OPENVPN_APPLECRYPTO_CF_CFTIMER_H
|
||||||
|
|
||||||
|
#include <openvpn/applecrypto/cf/cf.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
namespace CF {
|
||||||
|
OPENVPN_CF_WRAP(Timer, timer_cast, CFRunLoopTimerRef, CFRunLoopTimerGetTypeID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_APPLECRYPTO_CF_ERROR_H
|
||||||
|
#define OPENVPN_APPLECRYPTO_CF_ERROR_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <CoreFoundation/CFBase.h>
|
||||||
|
|
||||||
|
#include <openvpn/common/exception.hpp>
|
||||||
|
|
||||||
|
// An exception object that encapsulates Apple Core Foundation errors.
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
|
||||||
|
// string exception class
|
||||||
|
class CFException : public std::exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CFException(const std::string& text)
|
||||||
|
{
|
||||||
|
errtxt = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
CFException(const std::string& text, const OSStatus status)
|
||||||
|
{
|
||||||
|
set_errtxt(text, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const char* what() const throw() { return errtxt.c_str(); }
|
||||||
|
std::string what_str() const { return errtxt; }
|
||||||
|
|
||||||
|
virtual ~CFException() throw() {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void set_errtxt(const std::string& text, const OSStatus status)
|
||||||
|
{
|
||||||
|
std::ostringstream s;
|
||||||
|
s << text << ": OSX Error code=" << status;
|
||||||
|
errtxt = s.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string errtxt;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace openvpn
|
||||||
|
|
||||||
|
#endif // OPENVPN_APPLECRYPTO_CF_ERROR_H
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_APPLECRYPTO_CRYPTO_API_H
|
||||||
|
#define OPENVPN_APPLECRYPTO_CRYPTO_API_H
|
||||||
|
|
||||||
|
#include <openvpn/applecrypto/crypto/cipher.hpp>
|
||||||
|
#include <openvpn/applecrypto/crypto/ciphergcm.hpp>
|
||||||
|
#include <openvpn/applecrypto/crypto/digest.hpp>
|
||||||
|
#include <openvpn/applecrypto/crypto/hmac.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
|
||||||
|
// type container for Apple Crypto-level API
|
||||||
|
struct AppleCryptoAPI {
|
||||||
|
// cipher
|
||||||
|
typedef AppleCrypto::CipherContext CipherContext;
|
||||||
|
typedef AppleCrypto::CipherContextGCM CipherContextGCM;
|
||||||
|
|
||||||
|
// digest
|
||||||
|
typedef AppleCrypto::DigestContext DigestContext;
|
||||||
|
|
||||||
|
// HMAC
|
||||||
|
typedef AppleCrypto::HMACContext HMACContext;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Wrap the Apple cipher API defined in <CommonCrypto/CommonCryptor.h> so
|
||||||
|
// that it can be used as part of the crypto layer of the OpenVPN core.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_APPLECRYPTO_CRYPTO_CIPHER_H
|
||||||
|
#define OPENVPN_APPLECRYPTO_CRYPTO_CIPHER_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <CommonCrypto/CommonCryptor.h>
|
||||||
|
|
||||||
|
#include <openvpn/common/size.hpp>
|
||||||
|
#include <openvpn/common/exception.hpp>
|
||||||
|
#include <openvpn/common/platform.hpp>
|
||||||
|
#include <openvpn/common/string.hpp>
|
||||||
|
#include <openvpn/crypto/static_key.hpp>
|
||||||
|
#include <openvpn/crypto/cryptoalgs.hpp>
|
||||||
|
#include <openvpn/applecrypto/cf/error.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
namespace AppleCrypto {
|
||||||
|
class CipherContext
|
||||||
|
{
|
||||||
|
CipherContext(const CipherContext&) = delete;
|
||||||
|
CipherContext& operator=(const CipherContext&) = delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
OPENVPN_SIMPLE_EXCEPTION(apple_cipher_mode_error);
|
||||||
|
OPENVPN_SIMPLE_EXCEPTION(apple_cipher_uninitialized);
|
||||||
|
OPENVPN_EXCEPTION(apple_cipher_error);
|
||||||
|
|
||||||
|
// mode parameter for constructor
|
||||||
|
enum {
|
||||||
|
MODE_UNDEF = -1,
|
||||||
|
ENCRYPT = kCCEncrypt,
|
||||||
|
DECRYPT = kCCDecrypt
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MAX_IV_LENGTH = 16,
|
||||||
|
CIPH_CBC_MODE = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
CipherContext()
|
||||||
|
: cinfo(nullptr), cref(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~CipherContext() { erase() ; }
|
||||||
|
|
||||||
|
void init(const CryptoAlgs::Type alg, const unsigned char *key, const int mode)
|
||||||
|
{
|
||||||
|
erase();
|
||||||
|
|
||||||
|
// check that mode is valid
|
||||||
|
if (!(mode == ENCRYPT || mode == DECRYPT))
|
||||||
|
throw apple_cipher_mode_error();
|
||||||
|
|
||||||
|
// initialize cipher context with cipher type
|
||||||
|
const CCCryptorStatus status = CCCryptorCreate(mode,
|
||||||
|
cipher_type(alg),
|
||||||
|
kCCOptionPKCS7Padding,
|
||||||
|
key,
|
||||||
|
CryptoAlgs::key_length(alg),
|
||||||
|
nullptr,
|
||||||
|
&cref);
|
||||||
|
if (status != kCCSuccess)
|
||||||
|
throw CFException("CipherContext: CCCryptorCreate", status);
|
||||||
|
|
||||||
|
cinfo = CryptoAlgs::get_ptr(alg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset(const unsigned char *iv)
|
||||||
|
{
|
||||||
|
check_initialized();
|
||||||
|
const CCCryptorStatus status = CCCryptorReset(cref, iv);
|
||||||
|
if (status != kCCSuccess)
|
||||||
|
throw CFException("CipherContext: CCCryptorReset", status);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool update(unsigned char *out, const size_t max_out_size,
|
||||||
|
const unsigned char *in, const size_t in_size,
|
||||||
|
size_t& out_acc)
|
||||||
|
{
|
||||||
|
check_initialized();
|
||||||
|
size_t dataOutMoved;
|
||||||
|
const CCCryptorStatus status = CCCryptorUpdate(cref, in, in_size, out, max_out_size, &dataOutMoved);
|
||||||
|
if (status == kCCSuccess)
|
||||||
|
{
|
||||||
|
out_acc += dataOutMoved;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool final(unsigned char *out, const size_t max_out_size, size_t& out_acc)
|
||||||
|
{
|
||||||
|
check_initialized();
|
||||||
|
size_t dataOutMoved;
|
||||||
|
const CCCryptorStatus status = CCCryptorFinal(cref, out, max_out_size, &dataOutMoved);
|
||||||
|
if (status == kCCSuccess)
|
||||||
|
{
|
||||||
|
out_acc += dataOutMoved;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_initialized() const { return cinfo != nullptr; }
|
||||||
|
|
||||||
|
size_t iv_length() const
|
||||||
|
{
|
||||||
|
check_initialized();
|
||||||
|
return cinfo->iv_length();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t block_size() const
|
||||||
|
{
|
||||||
|
check_initialized();
|
||||||
|
return cinfo->block_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// return cipher mode (such as CIPH_CBC_MODE, etc.)
|
||||||
|
int cipher_mode() const
|
||||||
|
{
|
||||||
|
check_initialized();
|
||||||
|
return CIPH_CBC_MODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static CCAlgorithm cipher_type(const CryptoAlgs::Type alg)
|
||||||
|
{
|
||||||
|
switch (alg)
|
||||||
|
{
|
||||||
|
case CryptoAlgs::AES_128_CBC:
|
||||||
|
case CryptoAlgs::AES_192_CBC:
|
||||||
|
case CryptoAlgs::AES_256_CBC:
|
||||||
|
return kCCAlgorithmAES128;
|
||||||
|
case CryptoAlgs::DES_CBC:
|
||||||
|
return kCCAlgorithmDES;
|
||||||
|
case CryptoAlgs::DES_EDE3_CBC:
|
||||||
|
return kCCAlgorithm3DES;
|
||||||
|
#ifdef OPENVPN_PLATFORM_IPHONE
|
||||||
|
case CryptoAlgs::BF_CBC:
|
||||||
|
return kCCAlgorithmBlowfish;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
OPENVPN_THROW(apple_cipher_error, CryptoAlgs::name(alg) << ": not usable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void erase()
|
||||||
|
{
|
||||||
|
if (cinfo)
|
||||||
|
{
|
||||||
|
if (cref)
|
||||||
|
CCCryptorRelease(cref);
|
||||||
|
cref = nullptr;
|
||||||
|
cinfo = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_initialized() const
|
||||||
|
{
|
||||||
|
#ifdef OPENVPN_ENABLE_ASSERT
|
||||||
|
if (!cinfo)
|
||||||
|
throw apple_cipher_uninitialized();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const CryptoAlgs::Alg* cinfo;
|
||||||
|
CCCryptorRef cref;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,255 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Wrap the Apple digest API defined in <CommonCrypto/CommonDigest.h>
|
||||||
|
// so that it can be used as part of the crypto layer of the OpenVPN core.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_APPLECRYPTO_CRYPTO_DIGEST_H
|
||||||
|
#define OPENVPN_APPLECRYPTO_CRYPTO_DIGEST_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <CommonCrypto/CommonDigest.h>
|
||||||
|
#include <CommonCrypto/CommonHMAC.h>
|
||||||
|
|
||||||
|
#include <openvpn/common/size.hpp>
|
||||||
|
#include <openvpn/common/exception.hpp>
|
||||||
|
#include <openvpn/common/string.hpp>
|
||||||
|
#include <openvpn/crypto/cryptoalgs.hpp>
|
||||||
|
#include <openvpn/applecrypto/cf/error.hpp>
|
||||||
|
|
||||||
|
#define OPENVPN_DIGEST_CONTEXT(TYPE) CC_##TYPE##_CTX TYPE##_ctx
|
||||||
|
|
||||||
|
#define OPENVPN_DIGEST_ALG_CLASS(TYPE) \
|
||||||
|
class DigestAlgorithm##TYPE : public DigestAlgorithm \
|
||||||
|
{ \
|
||||||
|
public: \
|
||||||
|
DigestAlgorithm##TYPE() {} \
|
||||||
|
virtual int init(DigestCTX& ctx) const \
|
||||||
|
{ \
|
||||||
|
return CC_##TYPE##_Init(&ctx.u.TYPE##_ctx); \
|
||||||
|
} \
|
||||||
|
virtual int update(DigestCTX& ctx, const unsigned char *data, size_t size) const \
|
||||||
|
{ \
|
||||||
|
return CC_##TYPE##_Update(&ctx.u.TYPE##_ctx, data, size); \
|
||||||
|
} \
|
||||||
|
virtual int final(DigestCTX& ctx, unsigned char *md) const \
|
||||||
|
{ \
|
||||||
|
return CC_##TYPE##_Final(md, &ctx.u.TYPE##_ctx); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define OPENVPN_DIGEST_ALG_DECLARE(TYPE) const DigestAlgorithm##TYPE alg_##TYPE;
|
||||||
|
|
||||||
|
#define OPENVPN_DIGEST_INFO_DECLARE(TYPE) const DigestInfo info_##TYPE(CryptoAlgs::TYPE, &alg_##TYPE, kCCHmacAlg##TYPE)
|
||||||
|
|
||||||
|
#define OPENVPN_DIGEST_INFO_DECLARE_NO_HMAC(TYPE) const DigestInfo info_##TYPE(CryptoAlgs::TYPE, &alg_##TYPE, DigestInfo::NO_HMAC_ALG)
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
namespace AppleCrypto {
|
||||||
|
typedef CC_SHA256_CTX CC_SHA224_CTX;
|
||||||
|
typedef CC_SHA512_CTX CC_SHA384_CTX;
|
||||||
|
|
||||||
|
struct DigestCTX {
|
||||||
|
union {
|
||||||
|
OPENVPN_DIGEST_CONTEXT(MD4);
|
||||||
|
OPENVPN_DIGEST_CONTEXT(MD5);
|
||||||
|
OPENVPN_DIGEST_CONTEXT(SHA1);
|
||||||
|
OPENVPN_DIGEST_CONTEXT(SHA224);
|
||||||
|
OPENVPN_DIGEST_CONTEXT(SHA256);
|
||||||
|
OPENVPN_DIGEST_CONTEXT(SHA384);
|
||||||
|
OPENVPN_DIGEST_CONTEXT(SHA512);
|
||||||
|
} u;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DigestAlgorithm {
|
||||||
|
virtual int init(DigestCTX& ctx) const = 0;
|
||||||
|
virtual int update(DigestCTX& ctx, const unsigned char *data, size_t size) const = 0;
|
||||||
|
virtual int final(DigestCTX& ctx, unsigned char *md) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// individual digest algorithm classes (each inherits from DigestAlgorithm)
|
||||||
|
OPENVPN_DIGEST_ALG_CLASS(MD4);
|
||||||
|
OPENVPN_DIGEST_ALG_CLASS(MD5);
|
||||||
|
OPENVPN_DIGEST_ALG_CLASS(SHA1);
|
||||||
|
OPENVPN_DIGEST_ALG_CLASS(SHA224);
|
||||||
|
OPENVPN_DIGEST_ALG_CLASS(SHA256);
|
||||||
|
OPENVPN_DIGEST_ALG_CLASS(SHA384);
|
||||||
|
OPENVPN_DIGEST_ALG_CLASS(SHA512);
|
||||||
|
|
||||||
|
class DigestInfo
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum {
|
||||||
|
NO_HMAC_ALG = -1
|
||||||
|
};
|
||||||
|
|
||||||
|
DigestInfo(CryptoAlgs::Type type,
|
||||||
|
const DigestAlgorithm* digest_alg,
|
||||||
|
const CCHmacAlgorithm hmac_alg)
|
||||||
|
: type_(type),
|
||||||
|
digest_alg_(digest_alg),
|
||||||
|
hmac_alg_(hmac_alg) {}
|
||||||
|
|
||||||
|
CryptoAlgs::Type type() const { return type_; }
|
||||||
|
const char *name() const { return CryptoAlgs::name(type_); }
|
||||||
|
size_t size() const { return CryptoAlgs::size(type_); }
|
||||||
|
const DigestAlgorithm* digest_alg() const { return digest_alg_; }
|
||||||
|
CCHmacAlgorithm hmac_alg() const { return hmac_alg_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
CryptoAlgs::Type type_;
|
||||||
|
const DigestAlgorithm* digest_alg_;
|
||||||
|
CCHmacAlgorithm hmac_alg_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// instantiate individual digest algorithm class instances (each inherits from DigestAlgorithm),
|
||||||
|
// naming convention is alg_TYPE
|
||||||
|
OPENVPN_DIGEST_ALG_DECLARE(MD4);
|
||||||
|
OPENVPN_DIGEST_ALG_DECLARE(MD5);
|
||||||
|
OPENVPN_DIGEST_ALG_DECLARE(SHA1);
|
||||||
|
OPENVPN_DIGEST_ALG_DECLARE(SHA224);
|
||||||
|
OPENVPN_DIGEST_ALG_DECLARE(SHA256);
|
||||||
|
OPENVPN_DIGEST_ALG_DECLARE(SHA384);
|
||||||
|
OPENVPN_DIGEST_ALG_DECLARE(SHA512);
|
||||||
|
|
||||||
|
// instantiate individual digest info class instances (each is a DigestInfo),
|
||||||
|
// naming convention is info_TYPE
|
||||||
|
OPENVPN_DIGEST_INFO_DECLARE_NO_HMAC(MD4);
|
||||||
|
OPENVPN_DIGEST_INFO_DECLARE(MD5);
|
||||||
|
OPENVPN_DIGEST_INFO_DECLARE(SHA1);
|
||||||
|
OPENVPN_DIGEST_INFO_DECLARE(SHA224);
|
||||||
|
OPENVPN_DIGEST_INFO_DECLARE(SHA256);
|
||||||
|
OPENVPN_DIGEST_INFO_DECLARE(SHA384);
|
||||||
|
OPENVPN_DIGEST_INFO_DECLARE(SHA512);
|
||||||
|
|
||||||
|
class HMACContext;
|
||||||
|
|
||||||
|
class DigestContext
|
||||||
|
{
|
||||||
|
DigestContext(const DigestContext&) = delete;
|
||||||
|
DigestContext& operator=(const DigestContext&) = delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
friend class HMACContext;
|
||||||
|
|
||||||
|
OPENVPN_SIMPLE_EXCEPTION(apple_digest_uninitialized);
|
||||||
|
OPENVPN_SIMPLE_EXCEPTION(apple_digest_final_overflow);
|
||||||
|
OPENVPN_EXCEPTION(apple_digest_error);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MAX_DIGEST_SIZE = CC_SHA512_DIGEST_LENGTH // largest known is SHA512
|
||||||
|
};
|
||||||
|
|
||||||
|
DigestContext()
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
DigestContext(const CryptoAlgs::Type alg)
|
||||||
|
{
|
||||||
|
init(alg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init(const CryptoAlgs::Type alg)
|
||||||
|
{
|
||||||
|
clear();
|
||||||
|
info = digest_type(alg);
|
||||||
|
meth = info->digest_alg();
|
||||||
|
if (meth->init(ctx) != 1)
|
||||||
|
throw apple_digest_error("init");
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update(const unsigned char *in, const size_t size)
|
||||||
|
{
|
||||||
|
check_initialized();
|
||||||
|
if (meth->update(ctx, in, size) != 1)
|
||||||
|
throw apple_digest_error("update");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t final(unsigned char *out)
|
||||||
|
{
|
||||||
|
check_initialized();
|
||||||
|
if (meth->final(ctx, out) != 1)
|
||||||
|
throw apple_digest_error("final");
|
||||||
|
return info->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const
|
||||||
|
{
|
||||||
|
check_initialized();
|
||||||
|
return info->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_initialized() const { return initialized; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const DigestInfo *digest_type(const CryptoAlgs::Type alg)
|
||||||
|
{
|
||||||
|
switch (alg)
|
||||||
|
{
|
||||||
|
case CryptoAlgs::MD4:
|
||||||
|
return &info_MD4;
|
||||||
|
case CryptoAlgs::MD5:
|
||||||
|
return &info_MD5;
|
||||||
|
case CryptoAlgs::SHA1:
|
||||||
|
return &info_SHA1;
|
||||||
|
case CryptoAlgs::SHA224:
|
||||||
|
return &info_SHA224;
|
||||||
|
case CryptoAlgs::SHA256:
|
||||||
|
return &info_SHA256;
|
||||||
|
case CryptoAlgs::SHA384:
|
||||||
|
return &info_SHA384;
|
||||||
|
case CryptoAlgs::SHA512:
|
||||||
|
return &info_SHA512;
|
||||||
|
default:
|
||||||
|
OPENVPN_THROW(apple_digest_error, CryptoAlgs::name(alg) << ": not usable");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_initialized() const
|
||||||
|
{
|
||||||
|
#ifdef OPENVPN_ENABLE_ASSERT
|
||||||
|
if (!initialized)
|
||||||
|
throw apple_digest_uninitialized();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool initialized;
|
||||||
|
const DigestInfo *info;
|
||||||
|
const DigestAlgorithm *meth;
|
||||||
|
DigestCTX ctx;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef OPENVPN_DIGEST_CONTEXT
|
||||||
|
#undef OPENVPN_DIGEST_ALG_CLASS
|
||||||
|
#undef OPENVPN_DIGEST_ALG_DECLARE
|
||||||
|
#undef OPENVPN_DIGEST_INFO_DECLARE
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_APPLECRYPTO_CRYPTO_HMAC_H
|
||||||
|
#define OPENVPN_APPLECRYPTO_CRYPTO_HMAC_H
|
||||||
|
|
||||||
|
// Wrap the Apple HMAC API defined in <CommonCrypto/CommonHMAC.h> so that
|
||||||
|
// it can be used as part of the crypto layer of the OpenVPN core.
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include <CommonCrypto/CommonHMAC.h>
|
||||||
|
|
||||||
|
#include <openvpn/common/size.hpp>
|
||||||
|
#include <openvpn/common/exception.hpp>
|
||||||
|
#include <openvpn/applecrypto/crypto/digest.hpp>
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
namespace AppleCrypto {
|
||||||
|
class HMACContext
|
||||||
|
{
|
||||||
|
HMACContext(const HMACContext&) = delete;
|
||||||
|
HMACContext& operator=(const HMACContext&) = delete;
|
||||||
|
|
||||||
|
public:
|
||||||
|
OPENVPN_EXCEPTION(digest_cannot_be_used_with_hmac);
|
||||||
|
OPENVPN_SIMPLE_EXCEPTION(hmac_uninitialized);
|
||||||
|
OPENVPN_SIMPLE_EXCEPTION(hmac_keysize_error);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MAX_HMAC_SIZE = DigestContext::MAX_DIGEST_SIZE,
|
||||||
|
MAX_HMAC_KEY_SIZE = 128,
|
||||||
|
};
|
||||||
|
|
||||||
|
HMACContext()
|
||||||
|
{
|
||||||
|
state = PRE;
|
||||||
|
}
|
||||||
|
|
||||||
|
HMACContext(const CryptoAlgs::Type digest, const unsigned char *key, const size_t key_size)
|
||||||
|
{
|
||||||
|
init(digest, key, key_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
~HMACContext()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void init(const CryptoAlgs::Type digest, const unsigned char *key, const size_t key_size)
|
||||||
|
{
|
||||||
|
state = PRE;
|
||||||
|
info = DigestContext::digest_type(digest);
|
||||||
|
digest_size_ = CryptoAlgs::size(digest);
|
||||||
|
hmac_alg = info->hmac_alg();
|
||||||
|
if (hmac_alg == DigestInfo::NO_HMAC_ALG)
|
||||||
|
throw digest_cannot_be_used_with_hmac(info->name());
|
||||||
|
if (key_size > MAX_HMAC_KEY_SIZE)
|
||||||
|
throw hmac_keysize_error();
|
||||||
|
std::memcpy(key_, key, key_size_ = key_size);
|
||||||
|
state = PARTIAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset() // Apple HMAC API is missing reset method, so we have to reinit
|
||||||
|
{
|
||||||
|
cond_reset(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void update(const unsigned char *in, const size_t size)
|
||||||
|
{
|
||||||
|
cond_reset(false);
|
||||||
|
CCHmacUpdate(&ctx, in, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t final(unsigned char *out)
|
||||||
|
{
|
||||||
|
cond_reset(false);
|
||||||
|
CCHmacFinal(&ctx, out);
|
||||||
|
return digest_size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const
|
||||||
|
{
|
||||||
|
if (!is_initialized())
|
||||||
|
throw hmac_uninitialized();
|
||||||
|
return digest_size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_initialized() const
|
||||||
|
{
|
||||||
|
return state >= PARTIAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void cond_reset(const bool force_init)
|
||||||
|
{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case PRE:
|
||||||
|
throw hmac_uninitialized();
|
||||||
|
case READY:
|
||||||
|
if (!force_init)
|
||||||
|
return;
|
||||||
|
case PARTIAL:
|
||||||
|
CCHmacInit(&ctx, hmac_alg, key_, key_size_);
|
||||||
|
state = READY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum State {
|
||||||
|
PRE=0,
|
||||||
|
PARTIAL,
|
||||||
|
READY
|
||||||
|
};
|
||||||
|
int state;
|
||||||
|
|
||||||
|
const DigestInfo *info;
|
||||||
|
CCHmacAlgorithm hmac_alg;
|
||||||
|
size_t key_size_;
|
||||||
|
size_t digest_size_;
|
||||||
|
unsigned char key_[MAX_HMAC_KEY_SIZE];
|
||||||
|
CCHmacContext ctx;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,493 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// Wrap the Apple SSL API as defined in <Security/SecureTransport.h>
|
||||||
|
// so that it can be used as the SSL layer by the OpenVPN core.
|
||||||
|
// NOTE: not used in production code.
|
||||||
|
|
||||||
|
// Note that the Apple SSL API is missing some functionality (as of
|
||||||
|
// Mac OS X 10.8) that makes it difficult to use as a drop in replacement
|
||||||
|
// for OpenSSL or MbedTLS. The biggest issue is that the API doesn't
|
||||||
|
// allow an SSL context to be built out of PEM-based certificates and
|
||||||
|
// keys. It requires an "Identity" in the Keychain that was imported
|
||||||
|
// by the user as a PKCS#12 file.
|
||||||
|
|
||||||
|
#ifndef OPENVPN_APPLECRYPTO_SSL_SSLCTX_H
|
||||||
|
#define OPENVPN_APPLECRYPTO_SSL_SSLCTX_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <Security/SecImportExport.h>
|
||||||
|
#include <Security/SecItem.h>
|
||||||
|
#include <Security/SecureTransport.h>
|
||||||
|
#include <Security/SecKey.h>
|
||||||
|
|
||||||
|
#include <openvpn/common/size.hpp>
|
||||||
|
#include <openvpn/common/exception.hpp>
|
||||||
|
#include <openvpn/common/mode.hpp>
|
||||||
|
#include <openvpn/buffer/buffer.hpp>
|
||||||
|
#include <openvpn/frame/frame.hpp>
|
||||||
|
#include <openvpn/frame/memq_stream.hpp>
|
||||||
|
#include <openvpn/pki/epkibase.hpp>
|
||||||
|
#include <openvpn/applecrypto/cf/cfsec.hpp>
|
||||||
|
#include <openvpn/applecrypto/cf/error.hpp>
|
||||||
|
#include <openvpn/ssl/tlsver.hpp>
|
||||||
|
#include <openvpn/ssl/sslconsts.hpp>
|
||||||
|
#include <openvpn/ssl/sslapi.hpp>
|
||||||
|
|
||||||
|
// An SSL Context is essentially a configuration that can be used
|
||||||
|
// to generate an arbitrary number of actual SSL connections objects.
|
||||||
|
|
||||||
|
// AppleSSLContext is an SSL Context implementation that uses the
|
||||||
|
// Mac/iOS SSL library as a backend.
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
|
||||||
|
// Represents an SSL configuration that can be used
|
||||||
|
// to instantiate actual SSL sessions.
|
||||||
|
class AppleSSLContext : public SSLFactoryAPI
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef RCPtr<AppleSSLContext> Ptr;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
MAX_CIPHERTEXT_IN = 64
|
||||||
|
};
|
||||||
|
|
||||||
|
// The data needed to construct an AppleSSLContext.
|
||||||
|
class Config : public SSLConfigAPI
|
||||||
|
{
|
||||||
|
friend class AppleSSLContext;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef RCPtr<Config> Ptr;
|
||||||
|
|
||||||
|
Config() {}
|
||||||
|
|
||||||
|
void load_identity(const std::string& subject_match)
|
||||||
|
{
|
||||||
|
identity = load_identity_(subject_match);
|
||||||
|
if (!identity())
|
||||||
|
OPENVPN_THROW(ssl_context_error, "AppleSSLContext: identity '" << subject_match << "' undefined");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual SSLFactoryAPI::Ptr new_factory()
|
||||||
|
{
|
||||||
|
return SSLFactoryAPI::Ptr(new AppleSSLContext(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void set_mode(const Mode& mode_arg)
|
||||||
|
{
|
||||||
|
mode = mode_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const Mode& get_mode() const
|
||||||
|
{
|
||||||
|
return mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void set_frame(const Frame::Ptr& frame_arg)
|
||||||
|
{
|
||||||
|
frame = frame_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void load(const OptionList& opt, const unsigned int lflags)
|
||||||
|
{
|
||||||
|
// client/server
|
||||||
|
if (lflags & LF_PARSE_MODE)
|
||||||
|
mode = opt.exists("client") ? Mode(Mode::CLIENT) : Mode(Mode::SERVER);
|
||||||
|
|
||||||
|
// identity
|
||||||
|
{
|
||||||
|
const std::string& subject_match = opt.get("identity", 1, 256);
|
||||||
|
load_identity(subject_match);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void set_external_pki_callback(ExternalPKIBase* external_pki_arg)
|
||||||
|
{
|
||||||
|
not_implemented("set_external_pki_callback");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void set_private_key_password(const std::string& pwd)
|
||||||
|
{
|
||||||
|
return not_implemented("set_private_key_password");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void load_ca(const std::string& ca_txt, bool strict)
|
||||||
|
{
|
||||||
|
return not_implemented("load_ca");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void load_crl(const std::string& crl_txt)
|
||||||
|
{
|
||||||
|
return not_implemented("load_crl");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void load_cert(const std::string& cert_txt)
|
||||||
|
{
|
||||||
|
return not_implemented("load_cert");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void load_cert(const std::string& cert_txt, const std::string& extra_certs_txt)
|
||||||
|
{
|
||||||
|
return not_implemented("load_cert");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void load_private_key(const std::string& key_txt)
|
||||||
|
{
|
||||||
|
return not_implemented("load_private_key");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void load_dh(const std::string& dh_txt)
|
||||||
|
{
|
||||||
|
return not_implemented("load_dh");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void set_debug_level(const int debug_level)
|
||||||
|
{
|
||||||
|
return not_implemented("set_debug_level");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void set_flags(const unsigned int flags_arg)
|
||||||
|
{
|
||||||
|
return not_implemented("set_flags");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void set_ns_cert_type(const NSCert::Type ns_cert_type_arg)
|
||||||
|
{
|
||||||
|
return not_implemented("set_ns_cert_type");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void set_remote_cert_tls(const KUParse::TLSWebType wt)
|
||||||
|
{
|
||||||
|
return not_implemented("set_remote_cert_tls");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void set_tls_remote(const std::string& tls_remote_arg)
|
||||||
|
{
|
||||||
|
return not_implemented("set_tls_remote");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void set_tls_version_min(const TLSVersion::Type tvm)
|
||||||
|
{
|
||||||
|
return not_implemented("set_tls_version_min");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void set_local_cert_enabled(const bool v)
|
||||||
|
{
|
||||||
|
return not_implemented("set_local_cert_enabled");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void set_enable_renegotiation(const bool v)
|
||||||
|
{
|
||||||
|
return not_implemented("set_enable_renegotiation");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void set_force_aes_cbc_ciphersuites(const bool v)
|
||||||
|
{
|
||||||
|
return not_implemented("set_force_aes_cbc_ciphersuites");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void set_rng(const RandomAPI::Ptr& rng_arg)
|
||||||
|
{
|
||||||
|
return not_implemented("set_rng");
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void not_implemented(const char *funcname)
|
||||||
|
{
|
||||||
|
OPENVPN_LOG("AppleSSL: " << funcname << " not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
Mode mode;
|
||||||
|
CF::Array identity; // as returned by load_identity
|
||||||
|
Frame::Ptr frame;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Represents an actual SSL session.
|
||||||
|
// Normally instantiated by AppleSSLContext::ssl().
|
||||||
|
class SSL : public SSLAPI
|
||||||
|
{
|
||||||
|
friend class AppleSSLContext;
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef RCPtr<SSL> Ptr;
|
||||||
|
|
||||||
|
virtual void start_handshake()
|
||||||
|
{
|
||||||
|
SSLHandshake(ssl);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ssize_t write_cleartext_unbuffered(const void *data, const size_t size)
|
||||||
|
{
|
||||||
|
size_t actual = 0;
|
||||||
|
const OSStatus status = SSLWrite(ssl, data, size, &actual);
|
||||||
|
if (status < 0)
|
||||||
|
{
|
||||||
|
if (status == errSSLWouldBlock)
|
||||||
|
return SSLConst::SHOULD_RETRY;
|
||||||
|
else
|
||||||
|
throw CFException("AppleSSLContext::SSL::write_cleartext failed", status);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return actual;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ssize_t read_cleartext(void *data, const size_t capacity)
|
||||||
|
{
|
||||||
|
if (!overflow)
|
||||||
|
{
|
||||||
|
size_t actual = 0;
|
||||||
|
const OSStatus status = SSLRead(ssl, data, capacity, &actual);
|
||||||
|
if (status < 0)
|
||||||
|
{
|
||||||
|
if (status == errSSLWouldBlock)
|
||||||
|
return SSLConst::SHOULD_RETRY;
|
||||||
|
else
|
||||||
|
throw CFException("AppleSSLContext::SSL::read_cleartext failed", status);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return actual;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw ssl_ciphertext_in_overflow();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool read_cleartext_ready() const
|
||||||
|
{
|
||||||
|
// fixme: need to detect data buffered at SSL layer
|
||||||
|
return !ct_in.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void write_ciphertext(const BufferPtr& buf)
|
||||||
|
{
|
||||||
|
if (ct_in.size() < MAX_CIPHERTEXT_IN)
|
||||||
|
ct_in.write_buf(buf);
|
||||||
|
else
|
||||||
|
overflow = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool read_ciphertext_ready() const
|
||||||
|
{
|
||||||
|
return !ct_out.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual BufferPtr read_ciphertext()
|
||||||
|
{
|
||||||
|
return ct_out.read_buf();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string ssl_handshake_details() const // fixme -- code me
|
||||||
|
{
|
||||||
|
return "[AppleSSL not implemented]";
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const AuthCert::Ptr& auth_cert() const
|
||||||
|
{
|
||||||
|
OPENVPN_THROW(ssl_context_error, "AppleSSL::SSL: auth_cert() not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
~SSL()
|
||||||
|
{
|
||||||
|
ssl_erase();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SSL(const AppleSSLContext& ctx)
|
||||||
|
{
|
||||||
|
ssl_clear();
|
||||||
|
try {
|
||||||
|
OSStatus s;
|
||||||
|
|
||||||
|
#ifdef OPENVPN_PLATFORM_IPHONE
|
||||||
|
// init SSL object, select client or server mode
|
||||||
|
if (ctx.mode().is_server())
|
||||||
|
ssl = SSLCreateContext(kCFAllocatorDefault, kSSLServerSide, kSSLStreamType);
|
||||||
|
else if (ctx.mode().is_client())
|
||||||
|
ssl = SSLCreateContext(kCFAllocatorDefault, kSSLClientSide, kSSLStreamType);
|
||||||
|
else
|
||||||
|
OPENVPN_THROW(ssl_context_error, "AppleSSLContext::SSL: unknown client/server mode");
|
||||||
|
if (ssl == nullptr)
|
||||||
|
throw CFException("SSLCreateContext failed");
|
||||||
|
|
||||||
|
// use TLS v1
|
||||||
|
s = SSLSetProtocolVersionMin(ssl, kTLSProtocol1);
|
||||||
|
if (s)
|
||||||
|
throw CFException("SSLSetProtocolVersionMin failed", s);
|
||||||
|
#else
|
||||||
|
// init SSL object, select client or server mode
|
||||||
|
if (ctx.mode().is_server())
|
||||||
|
s = SSLNewContext(true, &ssl);
|
||||||
|
else if (ctx.mode().is_client())
|
||||||
|
s = SSLNewContext(false, &ssl);
|
||||||
|
else
|
||||||
|
OPENVPN_THROW(ssl_context_error, "AppleSSLContext::SSL: unknown client/server mode");
|
||||||
|
if (s)
|
||||||
|
throw CFException("SSLNewContext failed", s);
|
||||||
|
|
||||||
|
// use TLS v1
|
||||||
|
s = SSLSetProtocolVersionEnabled(ssl, kSSLProtocol2, false);
|
||||||
|
if (s)
|
||||||
|
throw CFException("SSLSetProtocolVersionEnabled !S2 failed", s);
|
||||||
|
s = SSLSetProtocolVersionEnabled(ssl, kSSLProtocol3, false);
|
||||||
|
if (s)
|
||||||
|
throw CFException("SSLSetProtocolVersionEnabled !S3 failed", s);
|
||||||
|
s = SSLSetProtocolVersionEnabled(ssl, kTLSProtocol1, true);
|
||||||
|
if (s)
|
||||||
|
throw CFException("SSLSetProtocolVersionEnabled T1 failed", s);
|
||||||
|
#endif
|
||||||
|
// configure cert, private key, and supporting CAs via identity wrapper
|
||||||
|
s = SSLSetCertificate(ssl, ctx.identity()());
|
||||||
|
if (s)
|
||||||
|
throw CFException("SSLSetCertificate failed", s);
|
||||||
|
|
||||||
|
// configure ciphertext buffers
|
||||||
|
ct_in.set_frame(ctx.frame());
|
||||||
|
ct_out.set_frame(ctx.frame());
|
||||||
|
|
||||||
|
// configure the "connection" object to be self
|
||||||
|
s = SSLSetConnection(ssl, this);
|
||||||
|
if (s)
|
||||||
|
throw CFException("SSLSetConnection", s);
|
||||||
|
|
||||||
|
// configure ciphertext read/write callbacks
|
||||||
|
s = SSLSetIOFuncs(ssl, ct_read_func, ct_write_func);
|
||||||
|
if (s)
|
||||||
|
throw CFException("SSLSetIOFuncs failed", s);
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
ssl_erase();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static OSStatus ct_read_func(SSLConnectionRef cref, void *data, size_t *length)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
SSL *self = (SSL *)cref;
|
||||||
|
const size_t actual = self->ct_in.read((unsigned char *)data, *length);
|
||||||
|
const OSStatus ret = (*length == actual) ? 0 : errSSLWouldBlock;
|
||||||
|
*length = actual;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return errSSLInternal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static OSStatus ct_write_func(SSLConnectionRef cref, const void *data, size_t *length)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
SSL *self = (SSL *)cref;
|
||||||
|
self->ct_out.write((const unsigned char *)data, *length);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
return errSSLInternal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssl_clear()
|
||||||
|
{
|
||||||
|
ssl = nullptr;
|
||||||
|
overflow = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ssl_erase()
|
||||||
|
{
|
||||||
|
if (ssl)
|
||||||
|
{
|
||||||
|
#ifdef OPENVPN_PLATFORM_IPHONE
|
||||||
|
CFRelease(ssl);
|
||||||
|
#else
|
||||||
|
SSLDisposeContext(ssl);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
ssl_clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
SSLContextRef ssl; // underlying SSL connection object
|
||||||
|
MemQStream ct_in; // write ciphertext to here
|
||||||
|
MemQStream ct_out; // read ciphertext from here
|
||||||
|
bool overflow;
|
||||||
|
};
|
||||||
|
|
||||||
|
/////// start of main class implementation
|
||||||
|
|
||||||
|
// create a new SSL instance
|
||||||
|
virtual SSLAPI::Ptr ssl()
|
||||||
|
{
|
||||||
|
return SSL::Ptr(new SSL(*this));
|
||||||
|
}
|
||||||
|
|
||||||
|
// like ssl() above but verify hostname against cert CommonName and/or SubjectAltName
|
||||||
|
virtual SSLAPI::Ptr ssl(const std::string& hostname)
|
||||||
|
{
|
||||||
|
OPENVPN_THROW(ssl_context_error, "AppleSSLContext: ssl session with CommonName and/or SubjectAltName verification not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const Mode& mode() const
|
||||||
|
{
|
||||||
|
return config_->mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AppleSSLContext(Config* config)
|
||||||
|
: config_(config)
|
||||||
|
{
|
||||||
|
if (!config_->identity())
|
||||||
|
OPENVPN_THROW(ssl_context_error, "AppleSSLContext: identity undefined");
|
||||||
|
}
|
||||||
|
|
||||||
|
const Frame::Ptr& frame() const { return config_->frame; }
|
||||||
|
const CF::Array& identity() const { return config_->identity; }
|
||||||
|
|
||||||
|
// load an identity from keychain, return as an array that can
|
||||||
|
// be passed to SSLSetCertificate
|
||||||
|
static CF::Array load_identity_(const std::string& subj_match)
|
||||||
|
{
|
||||||
|
const CF::String label = CF::string(subj_match);
|
||||||
|
const void *keys[] = { kSecClass, kSecMatchSubjectContains, kSecMatchTrustedOnly, kSecReturnRef };
|
||||||
|
const void *values[] = { kSecClassIdentity, label(), kCFBooleanTrue, kCFBooleanTrue };
|
||||||
|
const CF::Dict query = CF::dict(keys, values, sizeof(keys)/sizeof(keys[0]));
|
||||||
|
CF::Generic result;
|
||||||
|
const OSStatus s = SecItemCopyMatching(query(), result.mod_ref());
|
||||||
|
if (!s && result.defined())
|
||||||
|
{
|
||||||
|
const void *asrc[] = { result() };
|
||||||
|
return CF::array(asrc, 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return CF::Array(); // not found
|
||||||
|
}
|
||||||
|
|
||||||
|
Config::Ptr config_;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef AppleSSLContext::Ptr AppleSSLContextPtr;
|
||||||
|
|
||||||
|
} // namespace openvpn
|
||||||
|
|
||||||
|
#endif // OPENVPN_APPLECRYPTO_SSL_SSLCTX_H
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
// OpenVPN -- An application to securely tunnel IP networks
|
||||||
|
// over a single port, with support for SSL/TLS-based
|
||||||
|
// session authentication and key exchange,
|
||||||
|
// packet encryption, packet authentication, and
|
||||||
|
// packet compression.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License Version 3
|
||||||
|
// as published by the Free Software Foundation.
|
||||||
|
//
|
||||||
|
// 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 General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program in the COPYING file.
|
||||||
|
// If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <openvpn/applecrypto/util/reach.hpp>
|
||||||
|
#include <openvpn/netconf/enumiface.hpp>
|
||||||
|
|
||||||
|
#ifndef OPENVPN_APPLECRYPTO_UTIL_IOSACTIVEIFACE_H
|
||||||
|
#define OPENVPN_APPLECRYPTO_UTIL_IOSACTIVEIFACE_H
|
||||||
|
|
||||||
|
namespace openvpn {
|
||||||
|
|
||||||
|
class iOSActiveInterface : public ReachabilityInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual Status reachable() const
|
||||||
|
{
|
||||||
|
if (ei.iface_up("en0"))
|
||||||
|
return ReachableViaWiFi;
|
||||||
|
else if (ei.iface_up("pdp_ip0"))
|
||||||
|
return ReachableViaWWAN;
|
||||||
|
else
|
||||||
|
return NotReachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool reachableVia(const std::string& net_type) const
|
||||||
|
{
|
||||||
|
const Status r = reachable();
|
||||||
|
if (net_type == "cellular")
|
||||||
|
return r == ReachableViaWWAN;
|
||||||
|
else if (net_type == "wifi")
|
||||||
|
return r == ReachableViaWiFi;
|
||||||
|
else
|
||||||
|
return r != NotReachable;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual std::string to_string() const
|
||||||
|
{
|
||||||
|
switch (reachable())
|
||||||
|
{
|
||||||
|
case ReachableViaWiFi:
|
||||||
|
return "ReachableViaWiFi";
|
||||||
|
case ReachableViaWWAN:
|
||||||
|
return "ReachableViaWWAN";
|
||||||
|
case NotReachable:
|
||||||
|
return "NotReachable";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
EnumIface ei;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user