commit 86cc97e55fe346502462284d2e636a2b3708163e Author: Sergey Abramchuk Date: Mon Feb 24 14:43:11 2020 +0300 Squashed 'Sources/OpenVPN3/' content from commit 0a6e0b6e54 git-subtree-dir: Sources/OpenVPN3 git-subtree-split: 0a6e0b6e542c2d19de1f416c4caccd899d72831a diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4a2d375 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +README.html +x64 +*.vcxproj.user +*.ipch diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..6b44bdb --- /dev/null +++ b/.travis.yml @@ -0,0 +1,58 @@ +dist: bionic +os: linux +language: cpp + +env: + global: + - secure: "dqiLqbzug/xs6F4Q9ei1pGpNf9Q6H3+iKN1W+P0TtODbCXPr/mLWdvHGVMIMqr7H7rBrIUPFPrfqd80nu3jQuQonjcHK/XyJJfmf5hUdhGAszSaixhWnGfVmn/VSV7/5+9DGAU3l9S6YZg4lvi12+cOrlblNgx8GeI5VdN/6HBSHkEqKNI56qn3Y+ugSdLeL1opmzlY58vRsCCmpBH8Ronn4tmSyi85/WZXfF43o9FGGJcygdh6QVWA1CDdNMeLTCt9ld+oToUIiFLiUrhfS1JpSvzysz2xsuEntxZaTMDYPyL4+O8Mj/scl6ejLLXzxTNa7AZOgySLBahf+F4b+yhL1deSVuu40MfxPW6XiM1jKy3KPH/GlYgM8CZQ3D1hQIq1CIUg8DgnTa06RUzevsR5DqDvz+EcPanFHE7dHGrPy9Rs/0y59dNHp3qWKjWMoSA06GerbF61XFOb4mcE29053kV8uxqIa5ZShZ/ndoLeVpQ4mZ+/XSkUybysVl0gWrKnnNNEPtqrdmKf+jlmKY0jyRPdwf425Ldn+wcbGw9ZEnkosYzqAhDBDX4OETAKLi8G0FEYECKKQcd1OX+HNvsOIyOAoLOj7H30F8UkPsjR3ysdIEmc6702ly06gDYjWmwQaCigL/1ktRKgf7ePB0HS+8fOa5SML7619kQrGrWA=" + - PREFIX="${HOME}/opt" + - ASIO_VERSION="90f32660cd503494b3707840cfbd5434d8e9dabe" + - LZ4_VERSION="1.8.3" + - MBEDTLS_VERSION="2.7.5" + - MBEDTLS_CFLAGS="-I${PREFIX}/include" + - MBEDTLS_LIBS="-lmbedtls -lmbedx509 -lmbedcrypto" + - OPENSSL_VERSION="1.0.2s" + - OPENSSL_CFLAGS="-I${PREFIX}/include" + - OPENSSL_LIBS="-lssl -lcrypto" + - COVERITY_BRANCH="master" + +matrix: + include: + - env: SSLLIB="openssl" + os: osx + osx_image: xcode10.2 + compiler: clang + - env: SSLLIB="mbedtls" + os: osx + osx_image: xcode10.2 + compiler: clang + - env: SSLLIB="openssl" RUN_COVERITY_SCAN="1" + os: linux + compiler: gcc + - env: SSLLIB="openssl" + os: linux + compiler: clang + - env: SSLLIB="mbedtls" + os: linux + compiler: gcc + - env: SSLLIB="mbedtls" + os: linux + compiler: clang + +addons: + apt: + packages: + - libboost-all-dev + - linux-libc-dev + +cache: + ccache: true + directories: + - download-cache + - ${HOME}/opt + +install: + - .travis/build-deps.sh + +script: + - .travis/build-check.sh diff --git a/.travis/build-check.sh b/.travis/build-check.sh new file mode 100755 index 0000000..5c8f2fa --- /dev/null +++ b/.travis/build-check.sh @@ -0,0 +1,75 @@ +#!/bin/sh +set -eux + +PREFIX="${PREFIX:-${HOME}/opt}" +RUN_COVERITY_SCAN="${RUN_COVERITY_SCAN:-0}" + +if [ "${TRAVIS_OS_NAME}" = "linux" ]; then + export LD_LIBRARY_PATH="${PREFIX}/lib:${LD_LIBRARY_PATH:-}" +fi + +if [ "${TRAVIS_OS_NAME}" = "osx" ]; then + export DYLD_LIBRARY_PATH="${PREFIX}/lib:${DYLD_LIBRARY_PATH:-}" +fi + + +if [ "${SSLLIB}" = "openssl" ]; then + SSL_LIBS="${OPENSSL_LIBS}" + SSL_CFLAGS="-DUSE_OPENSSL" +elif [ "${SSLLIB}" = "mbedtls" ]; then + SSL_LIBS="${MBEDTLS_LIBS}" + SSL_CFLAGS="-DUSE_MBEDTLS" +else + echo "Invalid crypto lib: ${SSLLIB}" + exit 1 +fi + +LIBS="${SSL_LIBS} -llz4" +CXXFLAGS="-O3 -std=c++14 -Wall -pthread \ + -DOPENVPN_SHOW_SESSION_TOKEN -DHAVE_LZ4 \ + -DUSE_ASIO -DASIO_STANDALONE -DASIO_NO_DEPRECATED ${SSL_CFLAGS}" + +if [ "${CC}" = "gcc" ]; then + CXXFLAGS="${CXXFLAGS} -fwhole-program -flto=4" +fi + +INCLUDEDIRS="-I../../asio/asio/include -I${PREFIX}/include -I../../" +LDFLAGS="-L${PREFIX}/lib" + +if [ "${TRAVIS_OS_NAME}" = "linux" ]; then + LDFLAGS="${LDFLAGS} -Wl,--no-as-needed" +fi + +if [ "${TRAVIS_OS_NAME}" = "osx" ]; then + CXXFLAGS="${CXXFLAGS} -stdlib=libc++ -arch x86_64" + LIBS="${LIBS} -framework Security \ + -framework CoreFoundation \ + -framework SystemConfiguration \ + -framework IOKit \ + -framework ApplicationServices" +fi + +( + cd test/ovpncli + ${CXX} ${CXXFLAGS} ${INCLUDEDIRS} ${LDFLAGS} cli.cpp -o cli ${LIBS} +) + +( + cd test/ssl + ${CXX} ${CXXFLAGS} -DNOERR ${INCLUDEDIRS} ${LDFLAGS} proto.cpp -o proto ${LIBS} + ./proto +) + +if [ "${RUN_COVERITY_SCAN}" = "1" -a "${TRAVIS_BRANCH}" = "${COVERITY_BRANCH}" ]; then + unset LD_LIBRARY_PATH #don't mess up SSL for curl/wget + + export COVERITY_SCAN_PROJECT_NAME="OpenVPN/openvpn3" + export COVERITY_SCAN_BRANCH_PATTERN="${COVERITY_BRANCH}" + export COVERITY_SCAN_NOTIFICATION_EMAIL="scan-reports@openvpn.net" + export COVERITY_SCAN_BUILD_COMMAND_PREPEND="cd test/ssl" + export COVERITY_SCAN_BUILD_COMMAND="${CXX} ${CXXFLAGS} ${INCLUDEDIRS} \ + ${LDFLAGS} proto.cpp -o proto ${LIBS}" + + # Ignore exit code, script exits with 1 if we're not on the right branch + curl -s "https://scan.coverity.com/scripts/travisci_build_coverity_scan.sh" | bash || true +fi diff --git a/.travis/build-deps.sh b/.travis/build-deps.sh new file mode 100755 index 0000000..184dd4c --- /dev/null +++ b/.travis/build-deps.sh @@ -0,0 +1,133 @@ +#!/bin/sh +set -eux + +# Set defaults +PREFIX="${PREFIX:-${HOME}/opt}" + +download_asio () { + if [ ! -d "download-cache/asio" ]; then + git clone https://github.com/chriskohlhoff/asio.git \ + download-cache/asio + else + ( + cd download-cache/asio + if [ "$(git log -1 --format=%H)" != "${ASIO_VERSION}" ]; then + git checkout master + git pull + git checkout ${ASIO_VERSION} + fi + ) + fi +} + +build_asio () { + ( + if [ ! -L asio ]; then + rm -Rf asio + ln -s download-cache/asio asio + fi + ) +} + +download_lz4 () { + if [ ! -f "download-cache/lz4-${LZ4_VERSION}.tar.gz" ]; then + wget "https://github.com/lz4/lz4/archive/v${LZ4_VERSION}.tar.gz" \ + -O download-cache/lz4-${LZ4_VERSION}.tar.gz + fi +} + +build_lz4 () { + if [ "$(cat ${PREFIX}/.lz4-version)" != "${LZ4_VERSION}" ]; then + tar zxf download-cache/lz4-${LZ4_VERSION}.tar.gz + ( + cd "lz4-${LZ4_VERSION}" + make default CC=$CC CXX=$CXX + make install PREFIX="${PREFIX}" + ) + echo "${LZ4_VERSION}" > "${PREFIX}/.lz4-version" + fi +} + +download_mbedtls () { + if [ ! -f "download-cache/mbedtls-${MBEDTLS_VERSION}-apache.tgz" ]; then + wget -P download-cache/ \ + "https://tls.mbed.org/download/mbedtls-${MBEDTLS_VERSION}-apache.tgz" + fi +} + +build_mbedtls () { + if [ "$(cat ${PREFIX}/.mbedtls-version)" != "${MBEDTLS_VERSION}" ]; then + tar zxf download-cache/mbedtls-${MBEDTLS_VERSION}-apache.tgz + ( + cd "mbedtls-${MBEDTLS_VERSION}" + make CC=$CC CXX=$CXX + make install DESTDIR="${PREFIX}" + ) + echo "${MBEDTLS_VERSION}" > "${PREFIX}/.mbedtls-version" + fi +} + +download_openssl () { + if [ ! -f "download-cache/openssl-${OPENSSL_VERSION}.tar.gz" ]; then + wget -P download-cache/ \ + "https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz" + fi +} + +build_openssl_linux () { + ( + cd "openssl-${OPENSSL_VERSION}/" + ./config shared --prefix="${PREFIX}" --openssldir="${PREFIX}" -DPURIFY + make all install_sw + ) +} + +build_openssl_osx () { + ( + cd "openssl-${OPENSSL_VERSION}/" + ./Configure darwin64-x86_64-cc shared \ + --prefix="${PREFIX}" --openssldir="${PREFIX}" -DPURIFY + make depend all install_sw + ) +} + +build_openssl () { + if [ "$(cat ${PREFIX}/.openssl-version)" != "${OPENSSL_VERSION}" ]; then + tar zxf "download-cache/openssl-${OPENSSL_VERSION}.tar.gz" + if [ "${TRAVIS_OS_NAME}" = "osx" ]; then + build_openssl_osx + elif [ "${TRAVIS_OS_NAME}" = "linux" ]; then + build_openssl_linux + fi + echo "${OPENSSL_VERSION}" > "${PREFIX}/.openssl-version" + fi +} + +# Enable ccache +if [ "${TRAVIS_OS_NAME}" != "osx" ] && [ -z ${CHOST+x} ]; then + # ccache not available on osx, see: + # https://github.com/travis-ci/travis-ci/issues/5567 + # also ccache not enabled for cross builds + mkdir -p "${HOME}/bin" + ln -s "$(which ccache)" "${HOME}/bin/${CXX}" + ln -s "$(which ccache)" "${HOME}/bin/${CC}" + PATH="${HOME}/bin:${PATH}" +fi + +# Download and build crypto lib +if [ "${SSLLIB}" = "openssl" ]; then + download_openssl + build_openssl +elif [ "${SSLLIB}" = "mbedtls" ]; then + download_mbedtls + build_mbedtls +else + echo "Invalid crypto lib: ${SSLLIB}" + exit 1 +fi + +download_asio +build_asio + +download_lz4 +build_lz4 diff --git a/CLA.rst b/CLA.rst new file mode 100644 index 0000000..594c636 --- /dev/null +++ b/CLA.rst @@ -0,0 +1,63 @@ +Contributor agreement for the OpenVPN project version 1.3 - December 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 `_" refers to +the AGPLv3 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 Inc. + +In addition: + +(e) I understand that OpenVPN 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 Inc. a license to do so for this +contribution. My grant is made on the condition that OpenVPN Inc. will make +any modification to this contribution available to the OpenVPN project under +the open source license indicated in the file. diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..7c6bf76 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,7 @@ +# Cmake in OpenVPN3 core is mainly used to get Clion editior support and to run unit tests. For normal +# Build instructions see the README.rst + +cmake_minimum_required(VERSION 3.5) + +add_subdirectory(test/unittests) +add_subdirectory(test/ovpncli) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst new file mode 100644 index 0000000..48213fd --- /dev/null +++ b/CONTRIBUTING.rst @@ -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 `_. diff --git a/COPYRIGHT.AGPLV3 b/COPYRIGHT.AGPLV3 new file mode 100644 index 0000000..dba13ed --- /dev/null +++ b/COPYRIGHT.AGPLV3 @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/LICENSE.rst b/LICENSE.rst new file mode 100644 index 0000000..8bf238b --- /dev/null +++ b/LICENSE.rst @@ -0,0 +1,15 @@ +OpenVPN 3 is distributed under +`GNU Affero General Public License version 3 `_ +with a special permission to link against OpenSSL: + +:: + + Additional permission under GNU AGPL 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. diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..550b0d4 --- /dev/null +++ b/README.rst @@ -0,0 +1,617 @@ +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 +``_. + +A simple command-line wrapper for the API is provided in +``_. + +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:: + + $ DL=~/Downloads + $ 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 ASIO=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 + + +Building the OpenVPN 3 client on Windows +---------------------------------------- + +Prerequisites: + +* Visual Studio 2017 +* Python 2.7 +* Perl (for building openssl) + +Clone the OpenVPN 3 source repo:: + + > c:\Temp>mkdir O3 + > c:\Temp>cd O3 + > c:\Temp\O3>git clone https://github.com/OpenVPN/openvpn3.git core + +Add environment variable ``O3`` with value ``c:\Temp\O3`` and reopen commmand prompt. + +Download and build dependencies:: + + > c:\Temp\O3>cd core\win + > c:\Temp\O3\core\win>set STATIC=1&& set DEBUG=1&& python buildep.py + +Now you can open project in Visual Studio. Project and solution files are +located in ``O3\core\win`` directory. + +You can also build the test client from command prompt:: + + > c:\Temp\O3\core\win>set STATIC=1&& set DEBUG=1&& python build.py + +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: ``_ + +The test code itself is here: ``_ + +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 + +The OpenVPN 3 core also includes unit tests, which are based on +Google Test framework. To run unit tests, you need to install +CMake and build Google Test. + +Building Google Test on Linux:: + + $ git clone https://github.com/google/googletest.git + $ cd googletest + $ cmake . && cmake --build . + +Building Google Test on Windows:: + + > git clone https://github.com/google/googletest.git + > cd googletest + > cmake -G "Visual Studio 14 2015 Win64" . + > cmake --build . + +After Google Test is built you are ready to build and run unit tests. + +Build and run tests on Linux:: + + $ cd ovpn3/core/test/unittests + $ GTEST_DIR=~/googletest ECHO=1 PROF=linux ASIO_DIR=~/asio MTLS_SYS=1 LZ4_SYS=1 NOSSL=1 $O3/core/scripts/build test_log + $ ./test_log + +Build and run tests on Windows:: + + $ cd ovpn3/core/win + $ python build.py ../test/unittests/test_log.cpp unittest + $ test_log.exe + +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 ``_ and +header-only library files under ``_. + +The consise definition of the client API is essentially ``class OpenVPNClient`` +in ``_ with several imporant extensions to +the API found in: + +* **class TunBuilderBase** in ``_ — + Provides an abstraction layer defining the *tun* interface, + and is especially useful for interfacing with an OS-layer VPN API. + +* **class ExternalPKIBase** in ``_ — + 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 ``_ — + Provides an abstraction layer for the delivery of logging messages. + +OpenVPN 3 includes a command-line reference client (``cli``) for +testing the API. See ``_. + +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 = ; + ... + +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 ``_ and ``_. +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 ``_ +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 ``_ — + The top-layer object in an OpenVPN client connection. +2. **class ClientProto::Session** in ``_ — + The OpenVPN client protocol object that subinstantiates the transport + and tun layer objects. +3. **class ProtoContext** in ``_ — + The core OpenVPN protocol implementation that is common to both + client and server. +4. **class ProtoStackBase** in ``_ — + 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 ``_. + +Currently, transport layer implementations are provided for: + +* **UDP** — ``_ +* **TCP** — ``_ +* **HTTP Proxy** — ``_ + +Tun Layer +......... + +OpenVPN 3 defines abstract base classes for Tun layer +implementations in ``_. + +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 ``_ + +2. Use an OS-specific model such as: + + * **Linux** — ``_ + * **Windows** — ``_ + * **Mac OS X** — ``_ + +Protocol Layer +.............. + +The OpenVPN protocol is implemented in **class ProtoContext** +in ``_. + +Options Processing +.................. + +The parsing and query of the OpenVPN config file +is implemented by ``class OptionList`` in +``_. + +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 ``_ +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 ``_, 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 ``_. + +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 ``_ 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 ``_. 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 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 ``_, + 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 (``_ and ``_) 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 (``_). + +* If you need to deal with configuration file options, + see ``class OptionList`` in ``_. + +* If you need to deal with time or time durations, use the + classes under ``_. + +* If you need to deal with IP addresses, see the comprehensive classes + under ``_. + +* In general, if you need a general-purpose library class or function, + look under ``_. 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 ``_. + +* If you need to create a new event type which can be transmitted + as a notification back to the client API user, see + ``_. + +* 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 ``_. + +* Use C++ destructors for automatic object cleanup, and so + that thrown exceptions will not leak objects. Alternatively, + use ``Cleanup`` in ``_ 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 ``_. + +License +------- + +See ``_. + \ No newline at end of file diff --git a/VersionNumbering.rst b/VersionNumbering.rst new file mode 100644 index 0000000..0d32e58 --- /dev/null +++ b/VersionNumbering.rst @@ -0,0 +1,63 @@ +OpenVPN 3 version numbering and release process +=============================================== + +OpenVPN 3 version numbers will always be prefixed with ``3.`` which +indicates the OpenVPN generation. This library is the third +generation of the OpenVPN protocol implementation. + +As of OpenVPN 3.2, we will use a single positive integer indicating a +release number as the version reference. + + +Git branches and versioning +--------------------------- +Main development will happen on the git master branch. This will not +contain any specific version. It is will be set to ``3.git:master``. +This branch will contain both stable and unstable code, which will be +bleeding edge at any time. Do not depend on git master for production code. + +Once features and fixes in git master has stabilized, they will be +merged into the ``stable`` branch. Code extracted from the stable branch +will contain the release number of the last release. The stable +branch is suitable for production code. + +It is not set up a specific plan for when releases will occur. We +might want to collect up a smaller set of features before defining it +ready as a release, depending on the size of the changes. At the +release time, the version string will be updated and tagged (with +a PGP signature). + +We should not pile up too many features for each release. It is +better to release often with smaller changesets. + + +Hot-fixes +--------- + +We will not do any patch number releases unless strictly needed for +older releases numbers. Such releases will be called hot-fixes and +will be handled in separate branches only when needed. These branches +will be named ``hotfix/3.X``; where X denotes the release number the +hotfix targets. Hotfixes need to update the version string as well +as attaching a git tag with the proper version number. + +**Hot-fixes should be avoided as much as possible** and we should +**encourage users to base their work on the stable branch** primarily. +Hot-fixes will only be used for highly critical issues which cannot +wait for a release or the feature gap to move to a newer release is +considered too big. But it should also only occur for releases which +are still relevant. + + +Examples +-------- + +git ``master`` branch: version string will be ``3.git:master`` + +git ``stable`` branch: version string will be ``3.2``, ``3.3``, etc + +hotfix for v3.2 will be in ``hotfix/3.2`` and the version string will be +``3.2.1`` + +Similarly, hotfix for v3.3 will be found in ``hotfix/3.3`` and the version +string will be ``3.3.1``. diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..06884d1 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,32 @@ +version: 1.0.{build} + +image: Visual Studio 2019 + +clone_folder: c:\ovpn3\core + +install: +- pip install rfc6266 requests +- if not exist "C:\strawberry" choco install strawberryperl -y +- set PATH=C:\strawberry\c\bin;C:\strawberry\perl\site\bin;C:\strawberry\perl\bin;%PATH% + +environment: + MSVC_DIR: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community + O3: C:\ovpn3 + STATIC: 1 + +before_build: +- cmd: cd win && python buildep.py + +after_build: +- cmd: copy c:\ovpn3\deps\amd64\openssl\out32dll\ssleay32.dll c:\ovpn3\core\win\x64\ReleaseOpenSSL\ +- cmd: copy c:\ovpn3\deps\amd64\openssl\out32dll\libeay32.dll c:\ovpn3\core\win\x64\ReleaseOpenSSL\ + +platform: x64 + +configuration: ReleaseOpenSSL + +artifacts: + - path: win\x64\ReleaseOpenSSL\cli.exe + - path: win\x64\ReleaseOpenSSL\*.dll + + diff --git a/client/ovpncli.cpp b/client/ovpncli.cpp new file mode 100644 index 0000000..6d23519 --- /dev/null +++ b/client/ovpncli.cpp @@ -0,0 +1,1420 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +// Implementation file for OpenVPNClient API defined in ovpncli.hpp. + +#include +#include +#include +#include +#include + +#include + +// Set up export of our public interface unless +// OPENVPN_CORE_API_VISIBILITY_HIDDEN is defined +#if defined(__GNUC__) +#define OPENVPN_CLIENT_EXPORT +#ifndef OPENVPN_CORE_API_VISIBILITY_HIDDEN +#pragma GCC visibility push(default) +#endif +#include "ovpncli.hpp" // public interface +#ifndef OPENVPN_CORE_API_VISIBILITY_HIDDEN +#pragma GCC visibility pop +#endif +#else +// no public interface export defined for this compiler +#define OPENVPN_CLIENT_EXPORT +#include "ovpncli.hpp" // public interface +#endif + +// debug settings (production setting in parentheses) + +//#define OPENVPN_DUMP_CONFIG // dump parsed configuration (comment out) +//#define OPENVPN_DEBUG_CLIPROTO // shows packets in/out (comment out) +#define OPENVPN_DEBUG_PROTO 1 // increases low-level protocol verbosity (1) +//#define OPENVPN_DEBUG_PROTO_DUMP // dump hex of transport-layer packets, requires OPENVPN_DEBUG_CLIPROTO (comment out) +//#define OPENVPN_DEBUG_VERBOSE_ERRORS // verbosely log Error::Type errors (comment out) +#define OPENVPN_DEBUG_TUN 2 // debug level for tun object (2) +#define OPENVPN_DEBUG_UDPLINK 2 // debug level for UDP link object (2) +#define OPENVPN_DEBUG_TCPLINK 2 // debug level for TCP link object (2) +#define OPENVPN_DEBUG_COMPRESS 1 // debug level for compression objects (1) +#define OPENVPN_DEBUG_REMOTELIST 0 // debug level for RemoteList object (0) +#define OPENVPN_DEBUG_TUN_BUILDER 0 // debug level for tun/builder/client.hpp (0) +//#define OPENVPN_SHOW_SESSION_TOKEN // show server-pushed auth-token (comment out) +//#define OPENVPN_DEBUG_TAPWIN // shows Windows TAP driver debug logging (comment out) + +// enable assertion checks (can safely be disabled in production) +//#define OPENVPN_ENABLE_ASSERT + +// force null tun device (useful for testing) +//#define OPENVPN_FORCE_TUN_NULL + +// log cleartext tunnel packets to file for debugging/analysis +//#define OPENVPN_PACKET_LOG "pkt.log" + +#ifndef OPENVPN_LOG +// log thread settings +#define OPENVPN_LOG_CLASS openvpn::ClientAPI::LogReceiver +#define OPENVPN_LOG_INFO openvpn::ClientAPI::LogInfo +#include // should be included early +#endif + +// log SSL handshake messages +#define OPENVPN_LOG_SSL(x) OPENVPN_LOG(x) + +// on Android and iOS, use TunBuilderBase abstraction +#include +#if (defined(OPENVPN_PLATFORM_ANDROID) || defined(OPENVPN_PLATFORM_IPHONE)) && !defined(OPENVPN_FORCE_TUN_NULL) && !defined(OPENVPN_EXTERNAL_TUN_FACTORY) +#define USE_TUN_BUILDER +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// copyright +#include + +namespace openvpn { + namespace ClientAPI { + + OPENVPN_SIMPLE_EXCEPTION(app_expired); + + class MySessionStats : public SessionStats + { + public: + typedef RCPtr Ptr; + + MySessionStats(OpenVPNClient* parent_arg) + : parent(parent_arg) + { + std::memset(errors, 0, sizeof(errors)); +#ifdef OPENVPN_DEBUG_VERBOSE_ERRORS + session_stats_set_verbose(true); +#endif + } + + static size_t combined_n() + { + return N_STATS + Error::N_ERRORS; + } + + static std::string combined_name(const size_t index) + { + if (index < N_STATS + Error::N_ERRORS) + { + if (index < N_STATS) + return stat_name(index); + else + return Error::name(index - N_STATS); + } + else + return ""; + } + + count_t combined_value(const size_t index) const + { + if (index < N_STATS + Error::N_ERRORS) + { + if (index < N_STATS) + return get_stat(index); + else + return errors[index - N_STATS]; + } + else + return 0; + } + + count_t stat_count(const size_t index) const + { + return get_stat_fast(index); + } + + count_t error_count(const size_t index) const + { + return errors[index]; + } + + void detach_from_parent() + { + parent = nullptr; + } + + virtual void error(const size_t err, const std::string* text=nullptr) + { + if (err < Error::N_ERRORS) + { +#ifdef OPENVPN_DEBUG_VERBOSE_ERRORS + if (text) + OPENVPN_LOG("ERROR: " << Error::name(err) << " : " << *text); + else + OPENVPN_LOG("ERROR: " << Error::name(err)); +#endif + ++errors[err]; + } + } + + private: + OpenVPNClient* parent; + count_t errors[Error::N_ERRORS]; + }; + + class MyClientEvents : public ClientEvent::Queue + { + public: + typedef RCPtr Ptr; + + MyClientEvents(OpenVPNClient* parent_arg) : parent(parent_arg) {} + + virtual void add_event(ClientEvent::Base::Ptr event) override + { + if (parent) + { + Event ev; + ev.name = event->name(); + ev.info = event->render(); + ev.error = event->is_error(); + ev.fatal = event->is_fatal(); + + // save connected event + if (event->id() == ClientEvent::CONNECTED) + last_connected = std::move(event); + else if (event->id() == ClientEvent::DISCONNECTED) + parent->on_disconnect(); + parent->event(ev); + } + } + + void get_connection_info(ConnectionInfo& ci) + { + ClientEvent::Base::Ptr connected = last_connected; + if (connected) + { + const ClientEvent::Connected* c = connected->connected_cast(); + if (c) + { + ci.user = c->user; + ci.serverHost = c->server_host; + ci.serverPort = c->server_port; + ci.serverProto = c->server_proto; + ci.serverIp = c->server_ip; + ci.vpnIp4 = c->vpn_ip4; + ci.vpnIp6 = c->vpn_ip6; + ci.gw4 = c->vpn_gw4; + ci.gw6 = c->vpn_gw6; + ci.clientIp = c->client_ip; + ci.tunName = c->tun_name; + ci.defined = true; + return; + } + } + ci.defined = false; + } + + void detach_from_parent() + { + parent = nullptr; + } + + private: + OpenVPNClient* parent; + ClientEvent::Base::Ptr last_connected; + }; + + class MySocketProtect : public SocketProtect + { + public: + MySocketProtect() : parent(nullptr) {} + + void set_parent(OpenVPNClient* parent_arg) + { + parent = parent_arg; + } + + bool socket_protect(int socket, IP::Addr endpoint) override + { + if (parent) + { +#if defined(OPENVPN_COMMAND_AGENT) && defined(OPENVPN_PLATFORM_WIN) + return WinCommandAgent::add_bypass_route(endpoint); +#elif defined(OPENVPN_COMMAND_AGENT) && defined(OPENVPN_PLATFORM_MAC) + return UnixCommandAgent::add_bypass_route(endpoint); +#else + return parent->socket_protect(socket, endpoint.to_string(), endpoint.is_ipv6()); +#endif + } + else + return true; + } + + void detach_from_parent() + { + parent = nullptr; + } + + private: + OpenVPNClient* parent; + }; + + class MyReconnectNotify : public ReconnectNotify + { + public: + MyReconnectNotify() : parent(nullptr) {} + + void set_parent(OpenVPNClient* parent_arg) + { + parent = parent_arg; + } + + void detach_from_parent() + { + parent = nullptr; + } + + virtual bool pause_on_connection_timeout() + { + if (parent) + return parent->pause_on_connection_timeout(); + else + return false; + } + + private: + OpenVPNClient* parent; + }; + + class MyRemoteOverride : public RemoteList::RemoteOverride + { + public: + void set_parent(OpenVPNClient* parent_arg) + { + parent = parent_arg; + } + + void detach_from_parent() + { + parent = nullptr; + } + + virtual RemoteList::Item::Ptr get() override + { + if (parent) + { + const std::string title = "remote-override"; + ClientAPI::RemoteOverride ro; + try { + parent->remote_override(ro); + } + catch (const std::exception& e) + { + ro.error = e.what(); + } + RemoteList::Item::Ptr ri(new RemoteList::Item); + if (ro.error.empty()) + { + if (!ro.ip.empty()) + ri->set_ip_addr(IP::Addr(ro.ip, title)); + if (ro.host.empty()) + ro.host = ro.ip; + HostPort::validate_host(ro.host, title); + HostPort::validate_port(ro.port, title); + ri->server_host = std::move(ro.host); + ri->server_port = std::move(ro.port); + ri->transport_protocol = Protocol::parse(ro.proto, Protocol::CLIENT_SUFFIX, title.c_str()); + } + else + throw Exception("remote override exception: " + ro.error); + return ri; + } + else + return RemoteList::Item::Ptr(); + } + + private: + OpenVPNClient* parent = nullptr; + }; + + class MyClockTick + { + public: + MyClockTick(openvpn_io::io_context& io_context, + OpenVPNClient* parent_arg, + const unsigned int ms) + : timer(io_context), + parent(parent_arg), + period(Time::Duration::milliseconds(ms)) + { + } + + void cancel() + { + timer.cancel(); + } + + void detach_from_parent() + { + parent = nullptr; + } + + void schedule() + { + timer.expires_after(period); + timer.async_wait([this](const openvpn_io::error_code& error) + { + if (!parent || error) + return; + try { + parent->clock_tick(); + } + catch (...) + { + } + schedule(); + }); + } + + private: + AsioTimer timer; + OpenVPNClient* parent; + const Time::Duration period; + }; + + namespace Private { + class ClientState + { + public: + // state objects + OptionList options; + EvalConfig eval; + MySocketProtect socket_protect; + MyReconnectNotify reconnect_notify; + MyRemoteOverride remote_override; + ClientCreds::Ptr creds; + MySessionStats::Ptr stats; + MyClientEvents::Ptr events; + ClientConnect::Ptr session; + std::unique_ptr clock_tick; + + // extra settings submitted by API client + std::string server_override; + std::string port_override; + Protocol proto_override; + IPv6Setting ipv6; + int conn_timeout = 0; + bool tun_persist = false; + bool wintun = false; + bool google_dns_fallback = false; + bool synchronous_dns_lookup = false; + bool autologin_sessions = false; + bool retry_on_auth_failed = false; + std::string private_key_password; + std::string external_pki_alias; + bool disable_client_cert = false; + int ssl_debug_level = 0; + int default_key_direction = -1; + bool force_aes_cbc_ciphersuites = false; + std::string tls_version_min_override; + std::string tls_cert_profile_override; + std::string gui_version; + std::string sso_methods; + bool allow_local_lan_access; + std::string hw_addr_override; + std::string platform_version; + ProtoContextOptions::Ptr proto_context_options; + PeerInfo::Set::Ptr extra_peer_info; + HTTPProxyTransport::Options::Ptr http_proxy_options; + unsigned int clock_tick_ms = 0; +#ifdef OPENVPN_GREMLIN + Gremlin::Config::Ptr gremlin_config; +#endif + bool alt_proxy = false; + bool dco = false; + bool echo = false; + bool info = false; + + template + void attach(OpenVPNClient* parent, + openvpn_io::io_context* io_context, + Stop* async_stop_global) + { + // only one attachment per instantiation allowed + if (attach_called) + throw Exception("ClientState::attach() can only be called once per ClientState instantiation"); + attach_called = true; + + // async stop + async_stop_global_ = async_stop_global; + + // io_context + if (io_context) + io_context_ = io_context; + else + { + io_context_ = new openvpn_io::io_context(1); // concurrency hint=1 + io_context_owned = true; + } + + // client stats + stats.reset(new SESSION_STATS(parent)); + + // client events + events.reset(new CLIENT_EVENTS(parent)); + + // socket protect + socket_protect.set_parent(parent); + + // reconnect notifications + reconnect_notify.set_parent(parent); + + // remote override + remote_override.set_parent(parent); + } + + ClientState() {} + + ~ClientState() + { + stop_scope_local.reset(); + stop_scope_global.reset(); + socket_protect.detach_from_parent(); + reconnect_notify.detach_from_parent(); + remote_override.detach_from_parent(); + if (clock_tick) + clock_tick->detach_from_parent(); + if (stats) + stats->detach_from_parent(); + if (events) + events->detach_from_parent(); + session.reset(); + if (io_context_owned) + delete io_context_; + } + + // foreign thread access + + void enable_foreign_thread_access() + { + foreign_thread_ready.store(true, std::memory_order_release); + } + + bool is_foreign_thread_access() + { + return foreign_thread_ready.load(std::memory_order_acquire); + } + + // io_context + + openvpn_io::io_context* io_context() + { + return io_context_; + } + + // async stop + + Stop* async_stop_local() + { + return &async_stop_local_; + } + + Stop* async_stop_global() + { + return async_stop_global_; + } + + void trigger_async_stop_local() + { + async_stop_local_.stop(); + } + + // disconnect + void on_disconnect() + { + if (clock_tick) + clock_tick->cancel(); + } + + void setup_async_stop_scopes() + { + stop_scope_local.reset(new AsioStopScope(*io_context(), async_stop_local(), [this]() { + OPENVPN_ASYNC_HANDLER; + session->graceful_stop(); + })); + + stop_scope_global.reset(new AsioStopScope(*io_context(), async_stop_global(), [this]() { + OPENVPN_ASYNC_HANDLER; + trigger_async_stop_local(); + })); + } + + private: + ClientState(const ClientState&) = delete; + ClientState& operator=(const ClientState&) = delete; + + bool attach_called = false; + + Stop async_stop_local_; + Stop* async_stop_global_ = nullptr; + + std::unique_ptr stop_scope_local; + std::unique_ptr stop_scope_global; + + openvpn_io::io_context* io_context_ = nullptr; + bool io_context_owned = false; + + std::atomic foreign_thread_ready{false}; + }; + }; + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::init_process() + { + InitProcess::init(); + } + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::uninit_process() + { + InitProcess::uninit(); + } + + OPENVPN_CLIENT_EXPORT OpenVPNClient::OpenVPNClient() + { +#ifndef OPENVPN_NORESET_TIME + // We keep track of time as binary milliseconds since a time base, and + // this can wrap after ~48 days on 32 bit systems, so it's a good idea + // to periodically reinitialize the base. + Time::reset_base_conditional(); +#endif + + state = new Private::ClientState(); + state->proto_context_options.reset(new ProtoContextOptions()); + } + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::parse_config(const Config& config, EvalConfig& eval, OptionList& options) + { + try { + // validate proto_override + if (!config.protoOverride.empty()) + Protocol::parse(config.protoOverride, Protocol::NO_SUFFIX); + + // validate IPv6 setting + if (!config.ipv6.empty()) + IPv6Setting::parse(config.ipv6); + + // parse config + OptionList::KeyValueList kvl; + kvl.reserve(config.contentList.size()); + for (size_t i = 0; i < config.contentList.size(); ++i) + { + const KeyValue& kv = config.contentList[i]; + kvl.push_back(new OptionList::KeyValue(kv.key, kv.value)); + } + const ParseClientConfig cc = ParseClientConfig::parse(config.content, &kvl, options); +#ifdef OPENVPN_DUMP_CONFIG + std::cout << "---------- ARGS ----------" << std::endl; + std::cout << options.render(Option::RENDER_PASS_FMT|Option::RENDER_NUMBER|Option::RENDER_BRACKET) << std::endl; + std::cout << "---------- MAP ----------" << std::endl; + std::cout << options.render_map() << std::endl; +#endif + eval.error = cc.error(); + eval.message = cc.message(); + eval.userlockedUsername = cc.userlockedUsername(); + eval.profileName = cc.profileName(); + eval.friendlyName = cc.friendlyName(); + eval.autologin = cc.autologin(); + eval.externalPki = cc.externalPki(); + eval.staticChallenge = cc.staticChallenge(); + eval.staticChallengeEcho = cc.staticChallengeEcho(); + eval.privateKeyPasswordRequired = cc.privateKeyPasswordRequired(); + eval.allowPasswordSave = cc.allowPasswordSave(); + eval.remoteHost = config.serverOverride.empty() ? cc.firstRemoteListItem().host : config.serverOverride; + eval.remotePort = cc.firstRemoteListItem().port; + eval.remoteProto = cc.firstRemoteListItem().proto; + for (ParseClientConfig::ServerList::const_iterator i = cc.serverList().begin(); i != cc.serverList().end(); ++i) + { + ServerEntry se; + se.server = i->server; + se.friendlyName = i->friendlyName; + eval.serverList.push_back(se); + } + } + catch (const std::exception& e) + { + eval.error = true; + eval.message = Unicode::utf8_printable(std::string("ERR_PROFILE_GENERIC: ") + e.what(), 256); + } + } + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::parse_extras(const Config& config, EvalConfig& eval) + { + try { + state->server_override = config.serverOverride; + state->port_override = config.portOverride; + state->conn_timeout = config.connTimeout; + state->tun_persist = config.tunPersist; + state->wintun = config.wintun; + state->google_dns_fallback = config.googleDnsFallback; + state->synchronous_dns_lookup = config.synchronousDnsLookup; + state->autologin_sessions = config.autologinSessions; + state->retry_on_auth_failed = config.retryOnAuthFailed; + state->private_key_password = config.privateKeyPassword; + if (!config.protoOverride.empty()) + state->proto_override = Protocol::parse(config.protoOverride, Protocol::NO_SUFFIX); + if (!config.ipv6.empty()) + state->ipv6 = IPv6Setting::parse(config.ipv6); + if (!config.compressionMode.empty()) + state->proto_context_options->parse_compression_mode(config.compressionMode); + if (eval.externalPki) + state->external_pki_alias = config.externalPkiAlias; + state->disable_client_cert = config.disableClientCert; + state->ssl_debug_level = config.sslDebugLevel; + state->default_key_direction = config.defaultKeyDirection; + state->force_aes_cbc_ciphersuites = config.forceAesCbcCiphersuites; + state->tls_version_min_override = config.tlsVersionMinOverride; + state->tls_cert_profile_override = config.tlsCertProfileOverride; + state->allow_local_lan_access = config.allowLocalLanAccess; + state->gui_version = config.guiVersion; + state->sso_methods = config.ssoMethods; + state->platform_version = config.platformVersion; + state->hw_addr_override = config.hwAddrOverride; + state->alt_proxy = config.altProxy; + state->dco = config.dco; + state->echo = config.echo; + state->info = config.info; + state->clock_tick_ms = config.clockTickMS; + if (!config.gremlinConfig.empty()) + { +#ifdef OPENVPN_GREMLIN + state->gremlin_config.reset(new Gremlin::Config(config.gremlinConfig)); +#else + throw Exception("client not built with OPENVPN_GREMLIN"); +#endif + } + state->extra_peer_info = PeerInfo::Set::new_from_foreign_set(config.peerInfo); + if (!config.proxyHost.empty()) + { + HTTPProxyTransport::Options::Ptr ho(new HTTPProxyTransport::Options()); + ho->set_proxy_server(config.proxyHost, config.proxyPort); + ho->username = config.proxyUsername; + ho->password = config.proxyPassword; + ho->allow_cleartext_auth = config.proxyAllowCleartextAuth; + state->http_proxy_options = ho; + } + } + catch (const std::exception& e) + { + eval.error = true; + eval.message = Unicode::utf8_printable(e.what(), 256); + } + } + + OPENVPN_CLIENT_EXPORT long OpenVPNClient::max_profile_size() + { + return ProfileParseLimits::MAX_PROFILE_SIZE; + } + + OPENVPN_CLIENT_EXPORT MergeConfig OpenVPNClient::merge_config_static(const std::string& path, + bool follow_references) + { + ProfileMerge pm(path, "ovpn", "", follow_references ? ProfileMerge::FOLLOW_PARTIAL : ProfileMerge::FOLLOW_NONE, + ProfileParseLimits::MAX_LINE_SIZE, ProfileParseLimits::MAX_PROFILE_SIZE); + return build_merge_config(pm); + } + + OPENVPN_CLIENT_EXPORT MergeConfig OpenVPNClient::merge_config_string_static(const std::string& config_content) + { + ProfileMergeFromString pm(config_content, "", ProfileMerge::FOLLOW_NONE, + ProfileParseLimits::MAX_LINE_SIZE, ProfileParseLimits::MAX_PROFILE_SIZE); + return build_merge_config(pm); + } + + OPENVPN_CLIENT_EXPORT MergeConfig OpenVPNClient::build_merge_config(const ProfileMerge& pm) + { + MergeConfig ret; + ret.status = pm.status_string(); + ret.basename = pm.basename(); + if (pm.status() == ProfileMerge::MERGE_SUCCESS) + { + ret.refPathList = pm.ref_path_list(); + ret.profileContent = pm.profile_content(); + } + else + { + ret.errorText = pm.error(); + } + return ret; + } + + OPENVPN_CLIENT_EXPORT EvalConfig OpenVPNClient::eval_config_static(const Config& config) + { + EvalConfig eval; + OptionList options; + parse_config(config, eval, options); + return eval; + } + + // API client submits the configuration here before calling connect() + OPENVPN_CLIENT_EXPORT EvalConfig OpenVPNClient::eval_config(const Config& config) + { + // parse and validate configuration file + EvalConfig eval; + parse_config(config, eval, state->options); + if (eval.error) + return eval; + + // handle extra settings in config + parse_extras(config, eval); + state->eval = eval; + return eval; + } + + OPENVPN_CLIENT_EXPORT Status OpenVPNClient::provide_creds(const ProvideCreds& creds) + { + Status ret; + try { + ClientCreds::Ptr cc = new ClientCreds(); + cc->set_username(creds.username); + cc->set_password(creds.password); + cc->set_response(creds.response); + cc->set_dynamic_challenge_cookie(creds.dynamicChallengeCookie, creds.username); + cc->set_replace_password_with_session_id(creds.replacePasswordWithSessionID); + cc->enable_password_cache(creds.cachePassword); + state->creds = cc; + } + catch (const std::exception& e) + { + ret.error = true; + ret.message = Unicode::utf8_printable(e.what(), 256); + } + return ret; + } + + OPENVPN_CLIENT_EXPORT bool OpenVPNClient::socket_protect(int socket, std::string remote, bool ipv6) + { + return true; + } + + OPENVPN_CLIENT_EXPORT bool OpenVPNClient::parse_dynamic_challenge(const std::string& cookie, DynamicChallenge& dc) + { + try { + ChallengeResponse cr(cookie); + dc.challenge = cr.get_challenge_text(); + dc.echo = cr.get_echo(); + dc.responseRequired = cr.get_response_required(); + dc.stateID = cr.get_state_id(); + return true; + } + catch (const std::exception&) + { + return false; + } + } + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::process_epki_cert_chain(const ExternalPKICertRequest& req) + { + // Get cert and add to options list + if (!req.cert.empty()) + { + Option o; + o.push_back("cert"); + o.push_back(req.cert); + state->options.add_item(o); + } + + // Get the supporting chain, if it exists, and use + // it for ca (if ca isn't defined), or otherwise use + // it for extra-certs (if ca is defined but extra-certs + // is not). + if (!req.supportingChain.empty()) + { + if (!state->options.exists("ca")) + { + Option o; + o.push_back("ca"); + o.push_back(req.supportingChain); + state->options.add_item(o); + } + else if (!state->options.exists("extra-certs")) + { + Option o; + o.push_back("extra-certs"); + o.push_back(req.supportingChain); + state->options.add_item(o); + } + } + } + + OPENVPN_CLIENT_EXPORT Status OpenVPNClient::connect() + { +#if !defined(OPENVPN_OVPNCLI_SINGLE_THREAD) + openvpn_io::detail::signal_blocker signal_blocker; // signals should be handled by parent thread +#endif +#if defined(OPENVPN_LOG_LOGTHREAD_H) && !defined(OPENVPN_LOG_LOGBASE_H) +#ifdef OPENVPN_LOG_GLOBAL +#error ovpn3 core logging object only supports thread-local scope +#endif + Log::Context log_context(this); +#endif + + OPENVPN_LOG(ClientAPI::OpenVPNClient::platform()); + + return do_connect(); + } + + OPENVPN_CLIENT_EXPORT Status OpenVPNClient::do_connect() + { + Status status; + bool session_started = false; + try { + connect_attach(); +#if defined(OPENVPN_OVPNCLI_ASYNC_SETUP) + openvpn_io::post(*state->io_context(), [this]() { + do_connect_async(); + }); +#else + connect_setup(status, session_started); +#endif + connect_run(); + return status; + } + catch (const std::exception& e) + { + if (session_started) + connect_session_stop(); + return status_from_exception(e); + } + } + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::do_connect_async() + { + enum StopType { + NONE, + SESSION, + EXPLICIT, + }; + StopType stop_type = NONE; + Status status; + bool session_started = false; + try { + connect_setup(status, session_started); + } + catch (const std::exception& e) + { + stop_type = session_started ? SESSION : EXPLICIT; + status = status_from_exception(e); + } + if (status.error) + { + ClientEvent::Base::Ptr ev = new ClientEvent::ClientSetup(status.status, status.message); + state->events->add_event(std::move(ev)); + } + if (stop_type == SESSION) + connect_session_stop(); +#ifdef OPENVPN_IO_REQUIRES_STOP + if (stop_type == EXPLICIT) + state->io_context()->stop(); +#endif + } + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::connect_setup(Status& status, bool& session_started) + { + // set global MbedTLS debug level +#if defined(USE_MBEDTLS) || defined(USE_MBEDTLS_APPLE_HYBRID) + mbedtls_debug_set_threshold(state->ssl_debug_level); // fixme -- using a global method for this seems wrong +#endif + + // load options + ClientOptions::Config cc; + cc.cli_stats = state->stats; + cc.cli_events = state->events; + cc.server_override = state->server_override; + cc.port_override = state->port_override; + cc.proto_override = state->proto_override; + cc.ipv6 = state->ipv6; + cc.conn_timeout = state->conn_timeout; + cc.tun_persist = state->tun_persist; + cc.wintun = state->wintun; + cc.google_dns_fallback = state->google_dns_fallback; + cc.synchronous_dns_lookup = state->synchronous_dns_lookup; + cc.autologin_sessions = state->autologin_sessions; + cc.retry_on_auth_failed = state->retry_on_auth_failed; + cc.proto_context_options = state->proto_context_options; + cc.http_proxy_options = state->http_proxy_options; + cc.alt_proxy = state->alt_proxy; + cc.dco = state->dco; + cc.echo = state->echo; + cc.info = state->info; + cc.reconnect_notify = &state->reconnect_notify; + if (remote_override_enabled()) + cc.remote_override = &state->remote_override; + cc.private_key_password = state->private_key_password; + cc.disable_client_cert = state->disable_client_cert; + cc.ssl_debug_level = state->ssl_debug_level; + cc.default_key_direction = state->default_key_direction; + cc.force_aes_cbc_ciphersuites = state->force_aes_cbc_ciphersuites; + cc.tls_version_min_override = state->tls_version_min_override; + cc.tls_cert_profile_override = state->tls_cert_profile_override; + cc.gui_version = state->gui_version; + cc.sso_methods = state->sso_methods; + cc.hw_addr_override = state->hw_addr_override; + cc.platform_version = state->platform_version; + cc.extra_peer_info = state->extra_peer_info; + cc.stop = state->async_stop_local(); + cc.allow_local_lan_access = state->allow_local_lan_access; +#ifdef OPENVPN_GREMLIN + cc.gremlin_config = state->gremlin_config; +#endif + cc.socket_protect = &state->socket_protect; +#if defined(USE_TUN_BUILDER) + cc.builder = this; +#endif +#if defined(OPENVPN_EXTERNAL_TUN_FACTORY) + cc.extern_tun_factory = this; +#endif +#if defined(OPENVPN_EXTERNAL_TRANSPORT_FACTORY) + cc.extern_transport_factory = this; +#endif + // force Session ID use and disable password cache if static challenge is enabled + if (state->creds + && !state->creds->get_replace_password_with_session_id() + && !state->eval.autologin + && !state->eval.staticChallenge.empty()) + { + state->creds->set_replace_password_with_session_id(true); + state->creds->enable_password_cache(false); + } + + // external PKI +#if !defined(USE_APPLE_SSL) + if (state->eval.externalPki && !state->disable_client_cert) + { + if (!state->external_pki_alias.empty()) + { + ExternalPKICertRequest req; + req.alias = state->external_pki_alias; + external_pki_cert_request(req); + if (!req.error) + { + cc.external_pki = this; + process_epki_cert_chain(req); + } + else + { + external_pki_error(req, Error::EPKI_CERT_ERROR); + return; + } + } + else + { + status.error = true; + status.message = "Missing External PKI alias"; + return; + } + } +#endif + +#ifdef USE_OPENSSL + if (state->options.exists("allow-name-constraints")) + { + ClientEvent::Base::Ptr ev = new ClientEvent::UnsupportedFeature("allow-name-constraints", + "Always verified correctly with OpenSSL", false); + state->events->add_event(std::move(ev)); + } +#endif + + // build client options object + ClientOptions::Ptr client_options = new ClientOptions(state->options, cc); + + // configure creds in options + client_options->submit_creds(state->creds); + + // instantiate top-level client session + state->session.reset(new ClientConnect(*state->io_context(), client_options)); + + // convenience clock tick + if (state->clock_tick_ms) + { + state->clock_tick.reset(new MyClockTick(*state->io_context(), this, state->clock_tick_ms)); + state->clock_tick->schedule(); + } + + // raise an exception if app has expired + check_app_expired(); + + // start VPN + state->session->start(); // queue reads on socket/tun + session_started = true; + + // wire up async stop + state->setup_async_stop_scopes(); + + // prepare to start reactor + connect_pre_run(); + state->enable_foreign_thread_access(); + } + + OPENVPN_CLIENT_EXPORT Status OpenVPNClient::status_from_exception(const std::exception& e) + { + Status ret; + ret.error = true; + ret.message = Unicode::utf8_printable(e.what(), 256); + + // if exception is an ExceptionCode, translate the code + // to return status string + { + const ExceptionCode *ec = dynamic_cast(&e); + if (ec && ec->code_defined()) + ret.status = Error::name(ec->code()); + } + return ret; + } + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::connect_attach() + { + state->attach(this, + nullptr, + get_async_stop()); + } + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::connect_pre_run() + { + } + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::connect_run() + { + state->io_context()->run(); + } + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::connect_session_stop() + { + state->session->stop(); // On exception, stop client... + state->io_context()->poll(); // and execute completion handlers. + } + + OPENVPN_CLIENT_EXPORT ConnectionInfo OpenVPNClient::connection_info() + { + ConnectionInfo ci; + if (state->is_foreign_thread_access()) + { + MyClientEvents* events = state->events.get(); + if (events) + events->get_connection_info(ci); + } + return ci; + } + + OPENVPN_CLIENT_EXPORT bool OpenVPNClient::session_token(SessionToken& tok) + { + if (state->is_foreign_thread_access()) + { + ClientCreds* cc = state->creds.get(); + if (cc && cc->session_id_defined()) + { + tok.username = cc->get_username(); + tok.session_id = cc->get_password(); + return true; + } + } + return false; + } + + OPENVPN_CLIENT_EXPORT Stop* OpenVPNClient::get_async_stop() + { + return nullptr; + } + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::external_pki_error(const ExternalPKIRequestBase& req, const size_t err_type) + { + if (req.error) + { + if (req.invalidAlias) + { + ClientEvent::Base::Ptr ev = new ClientEvent::EpkiInvalidAlias(req.alias); + state->events->add_event(std::move(ev)); + } + + ClientEvent::Base::Ptr ev = new ClientEvent::EpkiError(req.errorText); + state->events->add_event(std::move(ev)); + + state->stats->error(err_type); + if (state->session) + state->session->dont_restart(); + } + } + + OPENVPN_CLIENT_EXPORT bool OpenVPNClient::sign(const std::string& data, std::string& sig, const std::string& algorithm) + { + ExternalPKISignRequest req; + req.data = data; + req.alias = state->external_pki_alias; + req.algorithm = algorithm; + external_pki_sign_request(req); // call out to derived class for RSA signature + if (!req.error) + { + sig = req.sig; + return true; + } + else + { + external_pki_error(req, Error::EPKI_SIGN_ERROR); + return false; + } + } + + OPENVPN_CLIENT_EXPORT bool OpenVPNClient::remote_override_enabled() + { + return false; + } + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::remote_override(RemoteOverride&) + { + } + + OPENVPN_CLIENT_EXPORT int OpenVPNClient::stats_n() + { + return (int)MySessionStats::combined_n(); + } + + OPENVPN_CLIENT_EXPORT std::string OpenVPNClient::stats_name(int index) + { + return MySessionStats::combined_name(index); + } + + OPENVPN_CLIENT_EXPORT long long OpenVPNClient::stats_value(int index) const + { + if (state->is_foreign_thread_access()) + { + MySessionStats* stats = state->stats.get(); + if (stats) + { + if (index == SessionStats::BYTES_IN || index == SessionStats::BYTES_OUT) + stats->dco_update(); + return stats->combined_value(index); + } + } + return 0; + } + + OPENVPN_CLIENT_EXPORT std::vector OpenVPNClient::stats_bundle() const + { + std::vector sv; + const size_t n = MySessionStats::combined_n(); + sv.reserve(n); + if (state->is_foreign_thread_access()) + { + MySessionStats* stats = state->stats.get(); + if (stats) + stats->dco_update(); + for (size_t i = 0; i < n; ++i) + sv.push_back(stats ? stats->combined_value(i) : 0); + } + else + { + for (size_t i = 0; i < n; ++i) + sv.push_back(0); + } + return sv; + } + + OPENVPN_CLIENT_EXPORT InterfaceStats OpenVPNClient::tun_stats() const + { + InterfaceStats ret; + if (state->is_foreign_thread_access()) + { + MySessionStats* stats = state->stats.get(); + + // The reason for the apparent inversion between in/out below is + // that TUN_*_OUT stats refer to data written to tun device, + // but from the perspective of tun interface, this is incoming + // data. Vice versa for TUN_*_IN. + if (stats) + { + ret.bytesOut = stats->stat_count(SessionStats::TUN_BYTES_IN); + ret.bytesIn = stats->stat_count(SessionStats::TUN_BYTES_OUT); + ret.packetsOut = stats->stat_count(SessionStats::TUN_PACKETS_IN); + ret.packetsIn = stats->stat_count(SessionStats::TUN_PACKETS_OUT); + ret.errorsOut = stats->error_count(Error::TUN_READ_ERROR); + ret.errorsIn = stats->error_count(Error::TUN_WRITE_ERROR); + return ret; + } + } + + ret.bytesOut = 0; + ret.bytesIn = 0; + ret.packetsOut = 0; + ret.packetsIn = 0; + ret.errorsOut = 0; + ret.errorsIn = 0; + return ret; + } + + OPENVPN_CLIENT_EXPORT TransportStats OpenVPNClient::transport_stats() const + { + TransportStats ret; + ret.lastPacketReceived = -1; // undefined + + if (state->is_foreign_thread_access()) + { + MySessionStats* stats = state->stats.get(); + if (stats) + { + stats->dco_update(); + ret.bytesOut = stats->stat_count(SessionStats::BYTES_OUT); + ret.bytesIn = stats->stat_count(SessionStats::BYTES_IN); + ret.packetsOut = stats->stat_count(SessionStats::PACKETS_OUT); + ret.packetsIn = stats->stat_count(SessionStats::PACKETS_IN); + + // calculate time since last packet received + { + const Time& lpr = stats->last_packet_received(); + if (lpr.defined()) + { + const Time::Duration dur = Time::now() - lpr; + const unsigned int delta = (unsigned int)dur.to_binary_ms(); + if (delta <= 60*60*24*1024) // only define for time periods <= 1 day + ret.lastPacketReceived = delta; + } + } + return ret; + } + } + + ret.bytesOut = 0; + ret.bytesIn = 0; + ret.packetsOut = 0; + ret.packetsIn = 0; + return ret; + } + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::stop() + { + if (state->is_foreign_thread_access()) + state->trigger_async_stop_local(); + } + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::pause(const std::string& reason) + { + if (state->is_foreign_thread_access()) + { + ClientConnect* session = state->session.get(); + if (session) + session->thread_safe_pause(reason); + } + } + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::resume() + { + if (state->is_foreign_thread_access()) + { + ClientConnect* session = state->session.get(); + if (session) + session->thread_safe_resume(); + } + } + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::reconnect(int seconds) + { + if (state->is_foreign_thread_access()) + { + ClientConnect* session = state->session.get(); + if (session) + session->thread_safe_reconnect(seconds); + } + } + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::post_cc_msg(const std::string& msg) + { + if (state->is_foreign_thread_access()) + { + ClientConnect* session = state->session.get(); + if (session) + session->thread_safe_post_cc_msg(msg); + } + } + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::clock_tick() + { + } + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::on_disconnect() + { + state->on_disconnect(); + } + + OPENVPN_CLIENT_EXPORT std::string OpenVPNClient::crypto_self_test() + { + return SelfTest::crypto_self_test(); + } + + OPENVPN_CLIENT_EXPORT int OpenVPNClient::app_expire() + { +#ifdef APP_EXPIRE_TIME + return APP_EXPIRE_TIME; +#else + return 0; +#endif + } + + OPENVPN_CLIENT_EXPORT void OpenVPNClient::check_app_expired() + { +#ifdef APP_EXPIRE_TIME + if (Time::now().seconds_since_epoch() >= APP_EXPIRE_TIME) + throw app_expired(); +#endif + } + + OPENVPN_CLIENT_EXPORT std::string OpenVPNClient::copyright() + { + return openvpn_copyright; + } + + OPENVPN_CLIENT_EXPORT std::string OpenVPNClient::platform() + { + std::string ret = platform_string(); +#ifdef PRIVATE_TUNNEL_PROXY + ret += " PT_PROXY"; +#endif +#ifdef ENABLE_DCO + ret += " DCO"; +#endif +#ifdef OPENVPN_GREMLIN + ret += " GREMLIN"; +#endif +#ifdef OPENVPN_DEBUG + ret += " built on " __DATE__ " " __TIME__; +#endif + return ret; + } + + OPENVPN_CLIENT_EXPORT OpenVPNClient::~OpenVPNClient() + { + delete state; + } + } +} diff --git a/client/ovpncli.hpp b/client/ovpncli.hpp new file mode 100644 index 0000000..9a1f5be --- /dev/null +++ b/client/ovpncli.hpp @@ -0,0 +1,633 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +// 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 +#include +#include + +#include +#include +#include +#include + +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 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 contentList; + + // Set to identity OpenVPN GUI version. + // Format should be "" + // Passed to server as IV_GUI_VER. + std::string guiVersion; + + // Set to a comma seperated list of supported SSO mechanisms that may + // be signalled via INFO_PRE to the client. + // "openurl" is to continue authentication by opening an url in a browser + // "crtext" gives a challenge response in text format that needs to + // responded via control channel. ( + // Passed to the server as IV_SSO + std::string ssoMethods; + + // Override the string that is passed as IV_HWADDR to the server + std::string hwAddrOverride; + + // Set the string that is passed to the server as IV_PLAT_VER + std::string platformVersion; + + // Use a different server than that specified in "remote" + // option of profile + std::string serverOverride; + + // Use a different port than that specified in "remote" + // option of profile + std::string portOverride; + + // 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; + + // if true, do synchronous DNS lookup. + bool synchronousDnsLookup = false; + + // Enable autologin sessions + bool autologinSessions = true; + + // If true, consider AUTH_FAILED to be a non-fatal error, + // and retry the connection after a pause. + bool retryOnAuthFailed = false; + + // 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 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; + + // Allow access to local LAN. This is for platforms like + // Android that disable local LAN access by default. + bool allowLocalLanAccess = false; + + // Periodic convenience clock tick in milliseconds. + // Will call clock_tick() at a frequency defined by this parameter. + // Set to 0 to disable. + unsigned int clockTickMS = 0; + + // Gremlin configuration (requires that the core is built with OPENVPN_GREMLIN) + std::string gremlinConfig; + + // Use wintun instead of tap-windows6 on Windows + bool wintun = false; + }; + + // 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) + : text(std::move(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 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. + // algorithm will determinate what signature is expected: + // RSA_PKCS1_PADDING means that + // data will be prefixed by an optional PKCS#1 digest prefix + // per RFC 3447. + // RSA_NO_PADDING mean so no padding should be done be the callee + struct ExternalPKISignRequest : public ExternalPKIRequestBase + { + std::string data; // data rendered as base64 (client reads) + std::string sig; // RSA signature, rendered as base64 (client writes) + std::string algorithm; + }; + + // 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; + std::string error; // if non-empty, indicates an error + }; + + namespace Private { + class ClientState; + }; + + // Top-level OpenVPN client class. + class OpenVPNClient : public TunBuilderBase, // expose tun builder virtual methods + public LogReceiver, // log message notification + public ExternalTun::Factory, // low-level tun override + public ExternalTransport::Factory,// low-level transport override + 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(). + // The remote and ipv6 are the remote host this socket will connect to + virtual bool socket_protect(int socket, std::string remote, bool ipv6); + + // 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 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&); + + // Periodic convenience clock tick, controlled by Config::clockTickMS + virtual void clock_tick(); + + // 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: + void connect_setup(Status&, bool&); + void do_connect_async(); + static Status status_from_exception(const std::exception&); + static void parse_config(const Config&, EvalConfig&, OptionList&); + void parse_extras(const Config&, EvalConfig&); + void external_pki_error(const ExternalPKIRequestBase&, const size_t); + void process_epki_cert_chain(const ExternalPKICertRequest&); + void check_app_expired(); + static MergeConfig build_merge_config(const ProfileMerge&); + + friend class MyClientEvents; + void on_disconnect(); + + // from ExternalPKIBase + virtual bool sign(const std::string& data, std::string& sig, const std::string& algorithm); + + // disable copy and assignment + OpenVPNClient(const OpenVPNClient&) = delete; + OpenVPNClient& operator=(const OpenVPNClient&) = delete; + }; + + } +} diff --git a/cmake/CMakeLists.txt.in b/cmake/CMakeLists.txt.in new file mode 100644 index 0000000..03bf3ff --- /dev/null +++ b/cmake/CMakeLists.txt.in @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.5) + +project(googletest-download NONE) + +include(ExternalProject) +ExternalProject_Add(googletest + GIT_REPOSITORY https://github.com/google/googletest.git + GIT_TAG master + SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src" + BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build" + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND "" + TEST_COMMAND "" + ) diff --git a/cmake/FindLZ4.cmake b/cmake/FindLZ4.cmake new file mode 100644 index 0000000..761b275 --- /dev/null +++ b/cmake/FindLZ4.cmake @@ -0,0 +1,9 @@ +find_path(LZ4_INCLUDE_DIR NAMES lz4.h) +find_library(LZ4_LIBRARY NAMES lz4) + +include(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS( + LZ4 DEFAULT_MSG + LZ4_LIBRARY LZ4_INCLUDE_DIR) + +mark_as_advanced(LZ4_INCLUDE_DIR LZ4_LIBRARY) \ No newline at end of file diff --git a/cmake/FindmbedTLS.cmake b/cmake/FindmbedTLS.cmake new file mode 100644 index 0000000..a262eaf --- /dev/null +++ b/cmake/FindmbedTLS.cmake @@ -0,0 +1,63 @@ +# - Try to find mbedTLS +# Once done this will define +# +# Read-Only variables +# MBEDTLS_FOUND - system has mbedTLS +# MBEDTLS_INCLUDE_DIR - the mbedTLS include directory +# MBEDTLS_LIBRARY_DIR - the mbedTLS library directory +# MBEDTLS_LIBRARIES - Link these to use mbedTLS +# MBEDTLS_LIBRARY - path to mbedTLS library +# MBEDX509_LIBRARY - path to mbedTLS X.509 library +# MBEDCRYPTO_LIBRARY - path to mbedTLS Crypto library + +FIND_PATH(MBEDTLS_INCLUDE_DIR mbedtls/version.h) + +IF(MBEDTLS_INCLUDE_DIR AND MBEDTLS_LIBRARIES) + # Already in cache, be silent + SET(MBEDTLS_FIND_QUIETLY TRUE) +ENDIF() + +FIND_LIBRARY(MBEDTLS_LIBRARY NAMES mbedtls libmbedtls libmbedx509) +FIND_LIBRARY(MBEDX509_LIBRARY NAMES mbedx509 libmbedx509) +FIND_LIBRARY(MBEDCRYPTO_LIBRARY NAMES mbedcrypto libmbedcrypto) + +IF(MBEDTLS_INCLUDE_DIR AND MBEDTLS_LIBRARY AND MBEDX509_LIBRARY AND MBEDCRYPTO_LIBRARY) + SET(MBEDTLS_FOUND TRUE) +ELSEIF(MBEDTLS_INCLUDE_DIR AND MBEDTLS_LIBRARY AND NOT MBEDX509_LIBRARY AND NOT MBEDCRYPTO_LIBRARY) + SET(MBEDTLS_FOUND TRUE) + SET(HACKY_OVPN_MBEDTLS TRUE) +ENDIF() + +IF(MBEDTLS_FOUND) + IF(HACKY_OVPN_MBEDTLS) + SET(MBEDTLS_LIBRARIES ${MBEDTLS_LIBRARY}) + ELSE() + SET(MBEDTLS_LIBRARIES ${MBEDTLS_LIBRARY} ${MBEDX509_LIBRARY} ${MBEDCRYPTO_LIBRARY}) + endif() + + IF(NOT MBEDTLS_FIND_QUIETLY) + MESSAGE(STATUS "Found mbedTLS:") + FILE(READ ${MBEDTLS_INCLUDE_DIR}/mbedtls/version.h MBEDTLSCONTENT) + STRING(REGEX MATCH "MBEDTLS_VERSION_STRING +\"[0-9|.]+\"" MBEDTLSMATCH ${MBEDTLSCONTENT}) + IF (MBEDTLSMATCH) + STRING(REGEX REPLACE "MBEDTLS_VERSION_STRING +\"([0-9|.]+)\"" "\\1" MBEDTLS_VERSION ${MBEDTLSMATCH}) + MESSAGE(STATUS " version ${MBEDTLS_VERSION}") + ENDIF(MBEDTLSMATCH) + MESSAGE(STATUS " TLS: ${MBEDTLS_LIBRARY}") + MESSAGE(STATUS " X509: ${MBEDX509_LIBRARY}") + MESSAGE(STATUS " Crypto: ${MBEDCRYPTO_LIBRARY}") + ENDIF(NOT MBEDTLS_FIND_QUIETLY) +ELSE(MBEDTLS_FOUND) + IF(mbedTLS_FIND_REQUIRED) + MESSAGE(FATAL_ERROR "Could not find mbedTLS") + ENDIF(mbedTLS_FIND_REQUIRED) +ENDIF(MBEDTLS_FOUND) + +MARK_AS_ADVANCED( + MBEDTLS_INCLUDE_DIR + MBEDTLS_LIBRARY_DIR + MBEDTLS_LIBRARIES + MBEDTLS_LIBRARY + MBEDX509_LIBRARY + MBEDCRYPTO_LIBRARY +) \ No newline at end of file diff --git a/cmake/dlgoogletest.cmake b/cmake/dlgoogletest.cmake new file mode 100644 index 0000000..ebd1a88 --- /dev/null +++ b/cmake/dlgoogletest.cmake @@ -0,0 +1,35 @@ + +# Google Test Unit testing +# Download and unpack googletest at configure time + +# Ensure that this only downloaded and added once +#include_guard(GLOBAL) +# Unfortunately include_guard requires cmake >= 3.10 +include(mypragmaonce) + +my_pragma_once() + + +configure_file(${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt.in googletest-download/CMakeLists.txt) +execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) +if(result) + message(FATAL_ERROR "CMake step for googletest failed: ${result}") +endif() +execute_process(COMMAND ${CMAKE_COMMAND} --build . + RESULT_VARIABLE result + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download ) +if(result) + message(FATAL_ERROR "Build step for googletest failed: ${result}") +endif() + +# Prevent overriding the parent project's compiler/linker +# settings on Windows +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + +# Add googletest directly to our build. This defines +# the gtest and gtest_main targets. +add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src + ${CMAKE_CURRENT_BINARY_DIR}/googletest-build + EXCLUDE_FROM_ALL) diff --git a/cmake/findcoredeps.cmake b/cmake/findcoredeps.cmake new file mode 100644 index 0000000..1961d76 --- /dev/null +++ b/cmake/findcoredeps.cmake @@ -0,0 +1,107 @@ +cmake_minimum_required(VERSION 3.5) + +set(CMAKE_CXX_STANDARD 14) + +#cmake_policy(SET CMP0079 NEW) + +set(CORE_DIR ${CMAKE_CURRENT_LIST_DIR}/..) + + +set(DEP_DIR ${CORE_DIR}/../deps CACHE PATH "Dependencies") +option(USE_MBEDTLS "Use mbed TLS instead of OpenSSL") + +if (DEFINED ENV{DEP_DIR}) + message(WARNING "Overriding DEP_DIR setting with environment variable") + set(DEP_DIR $ENV{DEP_DIR}) +endif () + +# Include our DEP_DIR in path used to find libraries + + +function(add_core_dependencies target) + if (APPLE) + set(PLAT osx) + elseif (WIN32) + set(PLAT amd64) + else () + set(PLAT linux) + endif () + + set(CORE_INCLUDES + ${CORE_DIR} + ${DEP_DIR}/asio/asio/include + ) + set(CORE_DEFINES + -DASIO_STANDALONE + -DUSE_ASIO + -DHAVE_LZ4 + -DLZ4_DISABLE_DEPRECATE_WARNINGS + -DMBEDTLS_DEPRECATED_REMOVED + ) + + if (WIN32) + list(APPEND CMAKE_PREFIX_PATH + ${DEP_DIR}/${PLAT}/mbedtls + ${DEP_DIR}/${PLAT}/lz4/lib + ) + list(APPEND CMAKE_LIBRARY_PATH + ${DEP_DIR}/${PLAT}/mbedtls/library + ) + list(APPEND CORE_INCLUDES + ${DEP_DIR}/${PLAT}/asio/asio/include + ${DEP_DIR}/${PLAT}/lz4/lz4/include + ${DEP_DIR}/${PLAT}/tap-windows/src + ) + list(APPEND CORE_DEFINES + -D_WIN32_WINNT=0x0600 + -DTAP_WIN_COMPONENT_ID=tap0901 + -D_CRT_SECURE_NO_WARNINGS + ) + set(EXTRA_LIBS fwpuclnt.lib Iphlpapi.lib) + target_compile_options(${target} PRIVATE "/bigobj") + else () + list(APPEND CMAKE_PREFIX_PATH + ${DEP_DIR}/mbedtls/mbedtls-${PLAT} + ${DEP_DIR}/lz4/lz4-${PLAT} + ) + list(APPEND CMAKE_LIBRARY_PATH + ${DEP_DIR}/mbedtls/mbedtls-${PLAT}/library + ) + endif () + + + if (${USE_MBEDTLS}) + find_package(mbedTLS REQUIRED) + + set(SSL_LIBRARY ${MBEDTLS_LIBRARIES}) + + list(APPEND CORE_DEFINES -DUSE_MBEDTLS) + + # The findmbedTLS does not set these automatically :( + list(APPEND CORE_INCLUDES ${MBEDTLS_INCLUDE_DIR}) + + else () + find_package(OpenSSL REQUIRED) + SET(SSL_LIBRARY OpenSSL::SSL) + list(APPEND CORE_DEFINES -DUSE_OPENSSL) + endif () + + if (APPLE) + find_library(coreFoundation CoreFoundation) + find_library(iokit IOKit) + find_library(coreServices CoreServices) + find_library(systemConfiguration SystemConfiguration) + target_link_libraries(${target} ${coreFoundation} ${iokit} ${coreServices} ${systemConfiguration} ${lz4} ${SSL_LIBRARY}) + endif() + + if(UNIX) + target_link_libraries(${target} pthread) + endif() + + find_package(LZ4 REQUIRED) + list(APPEND CORE_INCLUDES ${LZ4_INCLUDE_DIR}) + + target_include_directories(${target} PRIVATE ${CORE_INCLUDES}) + target_compile_definitions(${target} PRIVATE ${CORE_DEFINES}) + target_link_libraries(${target} ${SSL_LIBRARY} ${EXTRA_LIBS} ${LZ4_LIBRARY}) +endfunction() \ No newline at end of file diff --git a/cmake/mypragmaonce.cmake b/cmake/mypragmaonce.cmake new file mode 100644 index 0000000..bcc5469 --- /dev/null +++ b/cmake/mypragmaonce.cmake @@ -0,0 +1,8 @@ +macro(my_pragma_once) + set(__filename "${CMAKE_CURRENT_LIST_FILE}") + get_property(already_included GLOBAL PROPERTY "pr_${__filename}") + if(already_included) + return() + endif() + set_property(GLOBAL PROPERTY "pr_${__filename}" TRUE) +endmacro() diff --git a/deps/asio/build-asio b/deps/asio/build-asio new file mode 100755 index 0000000..91d96a8 --- /dev/null +++ b/deps/asio/build-asio @@ -0,0 +1,44 @@ +#!/usr/bin/env bash + +set -e +if [ -z "$O3" ]; then + echo O3 var must point to ovpn3 tree + exit 1 +fi +if [ -z "$DEP_DIR" ]; then + echo DEP_DIR var must point to dependency build folder + exit 1 +fi +if [ -z "$DL" ]; then + echo DL var must point to the download folder + exit 1 +fi + +. $O3/core/deps/lib-versions + +# source helper functions +. $O3/core/deps/functions.sh + +PACKAGE=${ASIO_VERSION} +FNAME=${ASIO_VERSION}.tar.gz +URL=https://github.com/chriskohlhoff/asio/archive/${ASIO_VERSION}.tar.gz +CSUM=${ASIO_CSUM} +DIST=asio + +download + +if [ "$NO_WIPE" = "1" ]; then + echo RETAIN existing source +else + echo WIPE and reunzip source + cd $DEP_DIR + rm -rf $DIST asio-$ASIO_VERSION + tar xfz $DL/$FNAME + cd asio-$ASIO_VERSION + + apply_patches "asio" + + cd .. + + cp -a asio-$ASIO_VERSION $DIST +fi diff --git a/deps/asio/patches/0001-Added-Apple-NAT64-support-when-both-ASIO_HAS_GETADDR.patch b/deps/asio/patches/0001-Added-Apple-NAT64-support-when-both-ASIO_HAS_GETADDR.patch new file mode 100644 index 0000000..becea4e --- /dev/null +++ b/deps/asio/patches/0001-Added-Apple-NAT64-support-when-both-ASIO_HAS_GETADDR.patch @@ -0,0 +1,48 @@ +From 00c0b1b7076ebc24735071f587f9501c1595a02b Mon Sep 17 00:00:00 2001 +From: James Yonan +Date: Mon, 19 Mar 2018 11:24:10 +0800 +Subject: [PATCH] Added Apple NAT64 support when both ASIO_HAS_GETADDRINFO and + ASIO_APPLE_NAT64 ar defined + +* 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 ad203b74..b17a60ed 100644 +--- a/asio/include/asio/detail/impl/socket_ops.ipp ++++ b/asio/include/asio/detail/impl/socket_ops.ipp +@@ -3339,6 +3339,23 @@ asio::error_code getaddrinfo(const char* host, + # endif + #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); +-- +2.21.0 + diff --git a/deps/asio/patches/0002-Added-randomize-method-to-asio-ip-tcp-resolver-resul.patch b/deps/asio/patches/0002-Added-randomize-method-to-asio-ip-tcp-resolver-resul.patch new file mode 100644 index 0000000..18ae1f7 --- /dev/null +++ b/deps/asio/patches/0002-Added-randomize-method-to-asio-ip-tcp-resolver-resul.patch @@ -0,0 +1,38 @@ +From fe57c9127cfc95b4673c6530f86edab5e6538425 Mon Sep 17 00:00:00 2001 +From: James Yonan +Date: Wed, 2 Sep 2015 12:18:48 -0700 +Subject: [PATCH] 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 3b3fad49..c070f7da 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 + #include ++#include + #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 ++ void randomize(Random& r) ++ { ++ std::shuffle(this->values_->begin(), this->values_->end(), r); ++ } ++ + private: + typedef std::vector > values_type; + }; +-- +2.21.0 + diff --git a/deps/asio/patches/0003-Added-user-code-hook-async_connect_post_open-to-be-c.patch b/deps/asio/patches/0003-Added-user-code-hook-async_connect_post_open-to-be-c.patch new file mode 100644 index 0000000..de2a100 --- /dev/null +++ b/deps/asio/patches/0003-Added-user-code-hook-async_connect_post_open-to-be-c.patch @@ -0,0 +1,38 @@ +From 80485636d5140c4b45679a4664eb7fe9e09f574f Mon Sep 17 00:00:00 2001 +From: James Yonan +Date: Mon, 27 Feb 2017 13:01:26 -0700 +Subject: [PATCH] Added user code hook async_connect_post_open() to be called + immediately after socket open in async_connect. + +--- + 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 42efbda4..4da85eb6 100644 +--- a/asio/include/asio/basic_socket.hpp ++++ b/asio/include/asio/basic_socket.hpp +@@ -950,6 +950,8 @@ public: + { + const protocol_type protocol = peer_endpoint.protocol(); + impl_.get_service().open(impl_.get_implementation(), protocol, open_ec); ++ if (!open_ec) ++ async_connect_post_open(protocol, open_ec); + } + + return async_initiate( +@@ -1800,6 +1802,11 @@ protected: + #endif + + 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; +-- +2.21.0 + diff --git a/deps/asio/patches/0004-error_code.ipp-Use-English-for-Windows-error-message.patch b/deps/asio/patches/0004-error_code.ipp-Use-English-for-Windows-error-message.patch new file mode 100644 index 0000000..81693de --- /dev/null +++ b/deps/asio/patches/0004-error_code.ipp-Use-English-for-Windows-error-message.patch @@ -0,0 +1,29 @@ +From af733fe9ce8345e06947dcf8b395d4736b1cb98c Mon Sep 17 00:00:00 2001 +From: Lev Stipakov +Date: Mon, 29 Apr 2019 10:26:13 +0300 +Subject: [PATCH] error_code.ipp: Use English for Windows error messages + +FormatMessageA doesn't work well with non-ASCII chars +so make it return error message in English. + +Signed-off-by: Lev Stipakov +--- + asio/include/asio/impl/error_code.ipp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/asio/include/asio/impl/error_code.ipp b/asio/include/asio/impl/error_code.ipp +index 55f5b361..3ef34fcd 100644 +--- a/asio/include/asio/impl/error_code.ipp ++++ b/asio/include/asio/impl/error_code.ipp +@@ -80,7 +80,7 @@ public: + DWORD length = ::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, 0, value, +- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (char*)&msg, 0, 0); ++ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), (char*)&msg, 0, 0); + detail::local_free_on_block_exit local_free_obj(msg); + if (length && msg[length - 1] == '\n') + msg[--length] = '\0'; +-- +2.16.2.windows.1 + diff --git a/deps/asio/snapshot-asio b/deps/asio/snapshot-asio new file mode 100755 index 0000000..2bd3e69 --- /dev/null +++ b/deps/asio/snapshot-asio @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +export NAME=asio +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +$DIR/../../scripts/snapshot diff --git a/deps/boost/atomic-1.55.0.patch b/deps/boost/atomic-1.55.0.patch new file mode 100644 index 0000000..021ee81 --- /dev/null +++ b/deps/boost/atomic-1.55.0.patch @@ -0,0 +1,87 @@ +--- boost/atomic/detail/cas128strong.hpp ++++ boost/atomic/detail/cas128strong.hpp +@@ -196,15 +196,17 @@ class base_atomic + + 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 + 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 + + 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 + + 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 + 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 + 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, +-- diff --git a/deps/boost/build-boost b/deps/boost/build-boost new file mode 100755 index 0000000..fcd10e5 --- /dev/null +++ b/deps/boost/build-boost @@ -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 <"-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 diff --git a/deps/boost/intrusive_ptr.patch b/deps/boost/intrusive_ptr.patch new file mode 100644 index 0000000..19717d9 --- /dev/null +++ b/deps/boost/intrusive_ptr.patch @@ -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(nullptr)))) : px( p ) + { + if( px != 0 && add_ref ) intrusive_ptr_add_ref( px ); + } +@@ -80,14 +80,14 @@ + intrusive_ptr( intrusive_ptr const & rhs ) + + #endif +- : px( rhs.get() ) ++ BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(intrusive_ptr_add_ref(static_cast(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(nullptr)))) : px( rhs.px ) + { + if( px != 0 ) intrusive_ptr_add_ref( px ); + } diff --git a/deps/boost/page_size.patch b/deps/boost/page_size.patch new file mode 100644 index 0000000..077015f --- /dev/null +++ b/deps/boost/page_size.patch @@ -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 + #include + +-#if defined(__ANDROID__) +-#include // http://code.google.com/p/android/issues/detail?id=39983 ++// JY modified ++#if defined(__ANDROID__) && !defined(PAGE_SIZE) ++#define PAGE_SIZE 4096 ++//#include // http://code.google.com/p/android/issues/detail?id=39983 + #endif + + #include diff --git a/deps/cityhash/build-cityhash b/deps/cityhash/build-cityhash new file mode 100755 index 0000000..d5835f6 --- /dev/null +++ b/deps/cityhash/build-cityhash @@ -0,0 +1,64 @@ +#!/usr/bin/env bash + +set -e +if [ -z "$O3" ]; then + echo O3 var must point to ovpn3 tree + exit 1 +fi +if [ -z "$DEP_DIR" ]; then + echo DEP_DIR var must point to dependency build folder + exit 1 +fi +if [ -z "$DL" ]; then + echo DL var must point to the download folder + 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 + +# source helper functions +. $O3/core/deps/functions.sh + +FNAME=cityhash-${CITYHASH_VERSION}.tar.gz +PN=${CITYHASH_VERSION#*-} +URL=https://codeload.github.com/google/cityhash/tar.gz/${CITYHASH_VERSION} +CSUM=${CITYHASH_CSUM} + +download + +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 $CITYHASH_VERSION + tar xfz $DL/cityhash-$CITYHASH_VERSION.tar.gz +fi + +DIST=$(pwd)/cityhash/cityhash-$PLATFORM +rm -rf $DIST +mkdir -p $DIST/include +mkdir $DIST/lib +cd cityhash-$CITYHASH_VERSION +CMD=./configure +echo $CMD +$CMD +CMD="$CC $PLATFORM_FLAGS $OTHER_COMPILER_FLAGS $LIB_OPT_LEVEL $LIB_FPIC -I. -Isrc -c src/city.cc" +echo $CMD +$CMD +$AR rc $DIST/lib/libcityhash.a city.o +$RANLIB $DIST/lib/libcityhash.a +cp src/city.h $DIST/include/ +exit 0 diff --git a/deps/functions.sh b/deps/functions.sh new file mode 100644 index 0000000..a9e932b --- /dev/null +++ b/deps/functions.sh @@ -0,0 +1,47 @@ +function check_download() +{ + if [ -f $DL/$FNAME ]; then + CHECK=$(shasum -a 256 $DL/$FNAME |awk '{printf $1};') + if [ "$CHECK" == "$CSUM" ]; then + return 0 + else + echo "Checksum mismatch for $FNAME. Was $CHECK, expected $CSUM" + fi + else + echo "$FNAME not found." + fi + + return -1 +} + +function download() +{ + check_download && return 0 + + rm -f $DL/$FNAME + if [ -n "$URL" ]; then + wget $URL -O $DL/$FNAME + else + echo URL must be specified + exit 1 + fi + + check_download || return -1 +} + +function apply_patches() +{ + DEP_NAME=$1 + + # change directory since git apply got confused when + # applying patches to files which are not found in index + DIR=$(pwd) + pushd ${DIR} + cd /tmp + # apply pre-generated patches + for file in $O3/core/deps/${DEP_NAME}/patches/*.patch; do + echo Applying patch: $file + git apply --directory ${DIR} --unsafe-path $file + done + popd +} diff --git a/deps/lib-versions b/deps/lib-versions new file mode 100644 index 0000000..6e4efab --- /dev/null +++ b/deps/lib-versions @@ -0,0 +1,24 @@ +export ASIO_VERSION=asio-1-14-0 +export ASIO_CSUM=bdb01a649c24d73ca4a836662e7af442d935313ed6deef6b07f17f3bc5f78d7a + +export LZ4_VERSION=lz4-1.8.3 +export LZ4_CSUM=33af5936ac06536805f9745e0b6d61da606a1f8b4cc5c04dd3cbaca3b9b4fc43 + +export MBEDTLS_VERSION=mbedtls-2.7.12 +export MBEDTLS_CSUM=d3a36dbc9f607747daa6875c1ab2e41f49eff5fc99d3436b4f3ac90c89f3c143 + +export JSONCPP_VERSION=1.8.4 +export JSONCPP_CSUM=c49deac9e0933bcb7044f08516861a2d560988540b23de2ac1ad443b219afdb6 + +export TAP_VERSION=0e30f5c13b3c7b0bdd60da915350f653e4c14d92 +export TAP_CSUM=8ff65f9e741c5ecfe1af904eaa38713f05639ce9457ef92041fd8e6b2a170315 + +export CITYHASH_VERSION=8af9b8c2b889d80c22d6bc26ba0df1afb79a30db +export CITYHASH_CSUM=f70368facd15735dffc77fe2b27ab505bfdd05be5e9166d94149a8744c212f49 + +export LZO_VERSION=lzo-2.10 +export LZO_CSUM=c0f892943208266f9b6543b3ae308fab6284c5c90e627931446fb49b4221a072 + +export OPENSSL_VERSION=openssl-1.1.1d +export OPENSSL_CSUM=1e3a91bc1f9dfce01af26026f856e064eab4c8ee0a8f457b5ae30b40b8b711f2 + diff --git a/deps/lz4/build-lz4 b/deps/lz4/build-lz4 new file mode 100755 index 0000000..53777d0 --- /dev/null +++ b/deps/lz4/build-lz4 @@ -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 "$DEP_DIR" ]; then + echo DEP_DIR var must point to dependency build folder + exit 1 +fi +if [ -z "$DL" ]; then + echo DL var must point to the download folder + 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 + +# source helper functions +. $O3/core/deps/functions.sh + +FNAME=${LZ4_VERSION}.tar.gz +PN=${LZ4_VERSION#*-} +URL=https://github.com/lz4/lz4/archive/v${PN}.tar.gz +CSUM=${LZ4_CSUM} + +download + +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 + +if [ "x$NO_BUILD" == x1 ]; then + echo "Not building" + exit +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 diff --git a/deps/lz4/snapshot-lz4 b/deps/lz4/snapshot-lz4 new file mode 100755 index 0000000..1074081 --- /dev/null +++ b/deps/lz4/snapshot-lz4 @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +export NAME=lz4 +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +$DIR/../../scripts/snapshot diff --git a/deps/lzo/build-lzo b/deps/lzo/build-lzo new file mode 100755 index 0000000..df96fb7 --- /dev/null +++ b/deps/lzo/build-lzo @@ -0,0 +1,80 @@ +#!/usr/bin/env bash + +set -e +if [ -z "$O3" ]; then + echo O3 var must point to ovpn3 tree + exit 1 +fi +if [ -z "$DEP_DIR" ]; then + echo DEP_DIR var must point to dependency build folder + 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 + +# source helper functions +. $O3/core/deps/functions.sh + +FNAME=${LZO_VERSION}.tar.gz +PN=${LZO_VERSION#*-} +URL=http://www.oberhumer.com/opensource/lzo/download/${LZO_VERSION}.tar.gz +CSUM=${LZO_CSUM} + +download + +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 + +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 diff --git a/deps/mbedtls/build-mbedtls b/deps/mbedtls/build-mbedtls new file mode 100755 index 0000000..a962ad9 --- /dev/null +++ b/deps/mbedtls/build-mbedtls @@ -0,0 +1,102 @@ +#!/bin/bash + +set -e +if [ -z "$O3" ]; then + echo O3 var must point to ovpn3 tree + exit 1 +fi +if [ -z "$DEP_DIR" ]; then + echo DEP_DIR var must point to dependency build folder + exit 1 +fi +if [ -z "$DL" ]; then + echo DL var must point to the download folder + 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 + +# source helper functions +. $O3/core/deps/functions.sh + +FNAME=${MBEDTLS_VERSION}-apache.tgz +PN=${MBEDTLS_VERSION#*-} +URL=https://tls.mbed.org/download/$MBEDTLS_VERSION-apache.tgz +CSUM=${MBEDTLS_CSUM} + +download + +# 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 + + apply_patches "mbedtls" +fi + +if [ "x$NO_BUILD" == x1 ]; then + echo "Not building" + exit 0 +fi + +if [[ "x$TARGET" == xlinux* || "x$TARGET" == xosx* ]]; then + # run unit tests and then clean + echo RUNNING CHECK + make check + echo CLEANING + make clean +fi + +echo BUILDING + +# 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 -DMBEDTLS_RELAXED_X509_DATE \ + $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 diff --git a/deps/mbedtls/patches/0001-relax-x509-date-format-check.patch b/deps/mbedtls/patches/0001-relax-x509-date-format-check.patch new file mode 100644 index 0000000..d5406e9 --- /dev/null +++ b/deps/mbedtls/patches/0001-relax-x509-date-format-check.patch @@ -0,0 +1,55 @@ +From 0554efae4e27b6a764def80f600394519ef1addb Mon Sep 17 00:00:00 2001 +From: Antonio Quartulli +Date: Tue, 20 Mar 2018 09:35:47 +0800 +Subject: [PATCH 1/2] relax x509 date format check + +Signed-off-by: Antonio Quartulli +--- + library/x509.c | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/library/x509.c b/library/x509.c +index 264c7fb0c..9372bcb92 100644 +--- a/library/x509.c ++++ b/library/x509.c +@@ -556,13 +556,20 @@ static int x509_parse_time( unsigned char **p, size_t len, size_t yearlen, + /* + * Parse seconds if present + */ +- if ( len >= 2 ) ++ if ( len >= 2 && **p >= '0' && **p <= '9' ) + { + CHECK( x509_parse_int( p, 2, &tm->sec ) ); + len -= 2; + } + else ++ { ++#if defined(MBEDTLS_RELAXED_X509_DATE) ++ /* if relaxed mode, allow seconds to be absent */ ++ tm->sec = 0; ++#else + return ( MBEDTLS_ERR_X509_INVALID_DATE ); ++#endif ++ } + + /* + * Parse trailing 'Z' if present +@@ -572,6 +579,15 @@ static int x509_parse_time( unsigned char **p, size_t len, size_t yearlen, + (*p)++; + len--; + } ++#if defined(MBEDTLS_RELAXED_X509_DATE) ++ else if ( len == 5 && **p == '+' ) ++ { ++ int tz; /* throwaway timezone */ ++ (*p)++; ++ CHECK( x509_parse_int( p, 4, &tz ) ); ++ return 0; ++ } ++#endif + + /* + * We should have parsed all characters at this point +-- +2.18.0 + diff --git a/deps/mbedtls/patches/0002-Enable-allowing-unsupported-critical-extensions-in-r.patch b/deps/mbedtls/patches/0002-Enable-allowing-unsupported-critical-extensions-in-r.patch new file mode 100644 index 0000000..f7f8f00 --- /dev/null +++ b/deps/mbedtls/patches/0002-Enable-allowing-unsupported-critical-extensions-in-r.patch @@ -0,0 +1,361 @@ +From 076f1437fe82de0b1f0ecf9a7ca031cd94c0c579 Mon Sep 17 00:00:00 2001 +From: Lev Stipakov +Date: Fri, 23 Feb 2018 17:12:49 +0200 +Subject: [PATCH] Enable allowing unsupported critical extensions in runtime + +When compile time flag MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION +is not set, certificate parsing fails if certificate contains unsupported critical extension. + +This patch allows to modify this behavior in runtime. + +Signed-off-by: Lev Stipakov +--- + include/mbedtls/oid.h | 13 +++- + include/mbedtls/ssl.h | 22 ++++++ + include/mbedtls/x509_crt.h | 2 + + library/oid.c | 81 ++++++++++++++++++---- + library/ssl_tls.c | 8 +++ + library/x509_crt.c | 10 ++- + tests/data_files/test-ca-nc.crt | 20 ++++++ + tests/suites/test_suite_x509parse.data | 6 ++ + tests/suites/test_suite_x509parse.function | 15 ++++ + 9 files changed, 162 insertions(+), 15 deletions(-) + create mode 100644 tests/data_files/test-ca-nc.crt + +diff --git a/include/mbedtls/oid.h b/include/mbedtls/oid.h +index 408645ece..b116736f8 100644 +--- a/include/mbedtls/oid.h ++++ b/include/mbedtls/oid.h +@@ -410,7 +410,7 @@ int mbedtls_oid_get_numeric_string( char *buf, size_t size, const mbedtls_asn1_b + + #if defined(MBEDTLS_X509_USE_C) || defined(MBEDTLS_X509_CREATE_C) + /** +- * \brief Translate an X.509 extension OID into local values ++ * \brief Translate supported X.509 extension OID into local values + * + * \param oid OID to use + * \param ext_type place to store the extension type +@@ -418,6 +418,17 @@ int mbedtls_oid_get_numeric_string( char *buf, size_t size, const mbedtls_asn1_b + * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND + */ + int mbedtls_oid_get_x509_ext_type( const mbedtls_asn1_buf *oid, int *ext_type ); ++ ++/** ++ * \brief Translate supported and unsupported X.509 extension OID into local values ++ * ++ * \param oid OID to use ++ * \param ext_type place to store the extension type ++ * \param is_supported place to store flag if extension is supported (1 - supported, 0 otherwise) ++ * ++ * \return 0 if successful, or MBEDTLS_ERR_OID_NOT_FOUND ++ */ ++int mbedtls_oid_get_x509_ext_type_supported( const mbedtls_asn1_buf *oid, int *ext_type, int *is_supported ); + #endif + + /** +diff --git a/include/mbedtls/ssl.h b/include/mbedtls/ssl.h +index 5fd6969da..1087ea166 100644 +--- a/include/mbedtls/ssl.h ++++ b/include/mbedtls/ssl.h +@@ -696,6 +696,10 @@ struct mbedtls_ssl_config + retransmission timeout (ms) */ + #endif + ++ uint32_t allowed_unsupported_critical_exts; /*!< Bit flags which represent runtime-enabled ++ unsupported critical extensions, e.g. ++ MBEDTLS_X509_EXT_NAME_CONSTRAINTS */ ++ + #if defined(MBEDTLS_SSL_RENEGOTIATION) + int renego_max_records; /*!< grace period for renegotiation */ + unsigned char renego_period[8]; /*!< value of the record counters +@@ -2298,6 +2302,24 @@ void mbedtls_ssl_conf_renegotiation_period( mbedtls_ssl_config *conf, + const unsigned char period[8] ); + #endif /* MBEDTLS_SSL_RENEGOTIATION */ + ++/** ++ * \brief Allows unsupported critical extensions ++ * ++ * Without compile-time flag MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION ++ * mbedTLS fails certificate verification if certificate contains ++ * unsupported critical extensions. ++ * ++ * This method allows to modify behavior in runtime by providing ++ * bit flags which represent unsupported extensions (for example MBEDTLS_X509_EXT_NAME_CONSTRAINTS) ++ * which should be allowed despite missing above mentioned compile-time flag. ++ * ++ * \param conf SSL configuration ++ * \param exts Bit flags which represent runtime-enabled unsupported critical extensions, ++ * e.g. MBEDTLS_X509_EXT_NAME_CONSTRAINTS ++ * ++ */ ++void mbedtls_ssl_conf_allow_unsupported_critical_exts( mbedtls_ssl_config *conf, uint32_t exts ); ++ + /** + * \brief Return the number of data bytes available to read + * +diff --git a/include/mbedtls/x509_crt.h b/include/mbedtls/x509_crt.h +index e72231ee8..9df19e52c 100644 +--- a/include/mbedtls/x509_crt.h ++++ b/include/mbedtls/x509_crt.h +@@ -90,6 +90,8 @@ typedef struct mbedtls_x509_crt + mbedtls_pk_type_t sig_pk; /**< Internal representation of the Public Key algorithm of the signature algorithm, e.g. MBEDTLS_PK_RSA */ + void *sig_opts; /**< Signature options to be passed to mbedtls_pk_verify_ext(), e.g. for RSASSA-PSS */ + ++ uint32_t allowed_unsupported_critical_exts; /**< Optional Bit flags which represent runtime-enabled unsupported critical extensions, e.g. MBEDTLS_X509_EXT_NAME_CONSTRAINTS */ ++ + struct mbedtls_x509_crt *next; /**< Next certificate in the CA-chain. */ + } + mbedtls_x509_crt; +diff --git a/library/oid.c b/library/oid.c +index edea950f8..a756d2801 100644 +--- a/library/oid.c ++++ b/library/oid.c +@@ -254,38 +254,95 @@ FN_OID_GET_ATTR1(mbedtls_oid_get_attr_short_name, oid_x520_attr_t, x520_attr, co + typedef struct { + mbedtls_oid_descriptor_t descriptor; + int ext_type; ++ int is_supported; + } oid_x509_ext_t; + + static const oid_x509_ext_t oid_x509_ext[] = + { + { +- { ADD_LEN( MBEDTLS_OID_BASIC_CONSTRAINTS ), "id-ce-basicConstraints", "Basic Constraints" }, +- MBEDTLS_X509_EXT_BASIC_CONSTRAINTS, ++ { ADD_LEN( MBEDTLS_OID_AUTHORITY_KEY_IDENTIFIER ), "id-ce-authorityKeyIdentifier", "Authority Key Identifier" }, ++ MBEDTLS_X509_EXT_AUTHORITY_KEY_IDENTIFIER, 0, + }, + { +- { ADD_LEN( MBEDTLS_OID_KEY_USAGE ), "id-ce-keyUsage", "Key Usage" }, +- MBEDTLS_X509_EXT_KEY_USAGE, ++ { ADD_LEN( MBEDTLS_OID_SUBJECT_KEY_IDENTIFIER ), "id-ce-subjectKeyIdentifier", "Subject Key Identifier" }, ++ MBEDTLS_X509_EXT_SUBJECT_KEY_IDENTIFIER, 0, + }, + { +- { ADD_LEN( MBEDTLS_OID_EXTENDED_KEY_USAGE ), "id-ce-extKeyUsage", "Extended Key Usage" }, +- MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE, ++ { ADD_LEN( MBEDTLS_OID_KEY_USAGE ), "id-ce-keyUsage", "Key Usage" }, ++ MBEDTLS_X509_EXT_KEY_USAGE, 1, + }, + { +- { ADD_LEN( MBEDTLS_OID_SUBJECT_ALT_NAME ), "id-ce-subjectAltName", "Subject Alt Name" }, +- MBEDTLS_X509_EXT_SUBJECT_ALT_NAME, ++ { ADD_LEN( MBEDTLS_OID_CERTIFICATE_POLICIES ), "id-ce-certificatePolicies", "Certificate Policies" }, ++ MBEDTLS_X509_EXT_CERTIFICATE_POLICIES, 0, + }, + { +- { ADD_LEN( MBEDTLS_OID_NS_CERT_TYPE ), "id-netscape-certtype", "Netscape Certificate Type" }, +- MBEDTLS_X509_EXT_NS_CERT_TYPE, ++ { ADD_LEN( MBEDTLS_OID_POLICY_MAPPINGS ), "id-ce-policyMappings", "Policy Mapping" }, ++ MBEDTLS_X509_EXT_POLICY_MAPPINGS, 0, ++ }, ++ { ++ { ADD_LEN( MBEDTLS_OID_ISSUER_ALT_NAME ), "id-ce-issuerAltName", "Issuer Alt Name" }, ++ MBEDTLS_X509_EXT_ISSUER_ALT_NAME, 0, ++ }, ++ { ++ { ADD_LEN( MBEDTLS_OID_SUBJECT_DIRECTORY_ATTRS ), "id-ce-subjectDirectoryAttributes", "Subject Directory Attributes" }, ++ MBEDTLS_X509_EXT_SUBJECT_DIRECTORY_ATTRS, 0, ++ }, ++ { ++ { ADD_LEN( MBEDTLS_OID_BASIC_CONSTRAINTS ), "id-ce-basicConstraints", "Basic Constraints" }, ++ MBEDTLS_X509_EXT_BASIC_CONSTRAINTS, 1, ++ }, ++ { ++ { ADD_LEN( MBEDTLS_OID_NAME_CONSTRAINTS ), "id-ce-nameConstraints", "Name Constraints" }, ++ MBEDTLS_X509_EXT_NAME_CONSTRAINTS, 0, ++ }, ++ { ++ { ADD_LEN( MBEDTLS_OID_POLICY_CONSTRAINTS ), "id-ce-policyConstraints", "Policy Constraints" }, ++ MBEDTLS_X509_EXT_POLICY_CONSTRAINTS, 0, ++ }, ++ { ++ { ADD_LEN( MBEDTLS_OID_EXTENDED_KEY_USAGE ), "id-ce-extKeyUsage", "Extended Key Usage" }, ++ MBEDTLS_X509_EXT_EXTENDED_KEY_USAGE, 1 ++ }, ++ { ++ { ADD_LEN( MBEDTLS_OID_CRL_DISTRIBUTION_POINTS ), "id-ce-cRLDistributionPoints", "CRL Distribution Points" }, ++ MBEDTLS_X509_EXT_CRL_DISTRIBUTION_POINTS, 0, ++ }, ++ { ++ { ADD_LEN( MBEDTLS_OID_INIHIBIT_ANYPOLICY ), "id-ce-inhibitAnyPolicy", "Inhibit Any Policy" }, ++ MBEDTLS_X509_EXT_INIHIBIT_ANYPOLICY, 0, ++ }, ++ { ++ { ADD_LEN( MBEDTLS_OID_FRESHEST_CRL ), "id-ce-freshestCRL", "Freshest CRL" }, ++ MBEDTLS_X509_EXT_FRESHEST_CRL, 0, ++ }, ++ { ++ { ADD_LEN( MBEDTLS_OID_SUBJECT_ALT_NAME ), "id-ce-subjectAltName", "Subject Alt Name" }, ++ MBEDTLS_X509_EXT_SUBJECT_ALT_NAME, 1 ++ }, ++ { ++ { ADD_LEN( MBEDTLS_OID_NS_CERT_TYPE ), "id-netscape-certtype", "Netscape Certificate Type" }, ++ MBEDTLS_X509_EXT_NS_CERT_TYPE, 1 + }, + { + { NULL, 0, NULL, NULL }, +- 0, ++ 0, 0 + }, + }; + + FN_OID_TYPED_FROM_ASN1(oid_x509_ext_t, x509_ext, oid_x509_ext) +-FN_OID_GET_ATTR1(mbedtls_oid_get_x509_ext_type, oid_x509_ext_t, x509_ext, int, ext_type) ++FN_OID_GET_ATTR2(mbedtls_oid_get_x509_ext_type_supported, oid_x509_ext_t, x509_ext, int, ext_type, int, is_supported) ++ ++int mbedtls_oid_get_x509_ext_type( const mbedtls_asn1_buf *oid, int *ext_type ) ++{ ++ int ret = 0; ++ int is_supported = 0; ++ ++ ret = mbedtls_oid_get_x509_ext_type_supported(oid, ext_type, &is_supported); ++ if( is_supported == 0 ) ++ ret = MBEDTLS_ERR_OID_NOT_FOUND; ++ ++ return( ret ); ++} + + static const mbedtls_oid_descriptor_t oid_ext_key_usage[] = + { +diff --git a/library/ssl_tls.c b/library/ssl_tls.c +index 1270ee9b8..2ce3f9b7d 100644 +--- a/library/ssl_tls.c ++++ b/library/ssl_tls.c +@@ -4668,6 +4668,9 @@ int mbedtls_ssl_parse_certificate( mbedtls_ssl_context *ssl ) + + mbedtls_x509_crt_init( ssl->session_negotiate->peer_cert ); + ++ ssl->session_negotiate->peer_cert->allowed_unsupported_critical_exts = ++ ssl->conf->allowed_unsupported_critical_exts; ++ + i += 3; + + while( i < ssl->in_hslen ) +@@ -6626,6 +6629,11 @@ void mbedtls_ssl_conf_renegotiation_period( mbedtls_ssl_config *conf, + } + #endif /* MBEDTLS_SSL_RENEGOTIATION */ + ++void mbedtls_ssl_conf_allow_unsupported_critical_exts( mbedtls_ssl_config *conf, uint32_t exts ) ++{ ++ conf->allowed_unsupported_critical_exts = exts; ++} ++ + #if defined(MBEDTLS_SSL_SESSION_TICKETS) + #if defined(MBEDTLS_SSL_CLI_C) + void mbedtls_ssl_conf_session_tickets( mbedtls_ssl_config *conf, int use_tickets ) +diff --git a/library/x509_crt.c b/library/x509_crt.c +index 3ad53a715..130b3ad1b 100644 +--- a/library/x509_crt.c ++++ b/library/x509_crt.c +@@ -539,6 +539,7 @@ static int x509_get_crt_ext( unsigned char **p, + int ret; + size_t len; + unsigned char *end_ext_data, *end_ext_octet; ++ int is_supported; + + if( *p == end ) + return( 0 ); +@@ -593,9 +594,9 @@ static int x509_get_crt_ext( unsigned char **p, + /* + * Detect supported extensions + */ +- ret = mbedtls_oid_get_x509_ext_type( &extn_oid, &ext_type ); ++ ret = mbedtls_oid_get_x509_ext_type_supported( &extn_oid, &ext_type, &is_supported ); + +- if( ret != 0 ) ++ if( ( ret != 0 ) || ( is_supported == 0 ) ) + { + /* No parser found, skip extension */ + *p = end_ext_octet; +@@ -603,6 +604,10 @@ static int x509_get_crt_ext( unsigned char **p, + #if !defined(MBEDTLS_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION) + if( is_critical ) + { ++ /* Do not fail if extension is found, but unsupported and allowed in runtime */ ++ if( ( ret == 0 ) && ( ext_type & crt->allowed_unsupported_critical_exts ) ) ++ continue; ++ + /* Data is marked as critical: fail */ + return( MBEDTLS_ERR_X509_INVALID_EXTENSIONS + + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ); +@@ -956,6 +961,7 @@ int mbedtls_x509_crt_parse_der( mbedtls_x509_crt *chain, const unsigned char *bu + + prev = crt; + mbedtls_x509_crt_init( crt->next ); ++ crt->next->allowed_unsupported_critical_exts = crt->allowed_unsupported_critical_exts; + crt = crt->next; + } + +diff --git a/tests/data_files/test-ca-nc.crt b/tests/data_files/test-ca-nc.crt +new file mode 100644 +index 000000000..7e0c56134 +--- /dev/null ++++ b/tests/data_files/test-ca-nc.crt +@@ -0,0 +1,20 @@ ++-----BEGIN CERTIFICATE----- ++MIIDSzCCAjOgAwIBAgIJAJx/NjT4C4viMA0GCSqGSIb3DQEBCwUAMBMxETAPBgNV ++BAMMCExlZXZpQ0E0MB4XDTE4MDEyNzE1MDczMloXDTI4MDEyNTE1MDczMlowEzER ++MA8GA1UEAwwITGVldmlDQTQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB ++AQDWN79RTlyFm5o0LVMSVjc68W0+gtl95xpaaD7IS6gDYjcbGnCwSefiq7y9rtck ++OM1A5Bzhj5+iWbmZStUmeJUhSGgxP/FxuUaAV0fsBGJ5jDrzmbhzDkHsNxDMB2ks ++XFyy4LfODcBs9TXxY43KUKuq/0meiT3WAaZWHMYle9vkQJM2l0RyH4IXHCHiIRwd ++2wntin6T9QOFJOc2ietNb7KsXVne81wb7h9BVMsjCIAsbPpHa+PZQs1xFuxmRxCs ++kpavnMy+SqevHhvqtvbHppcXYtZspTnkVoXWUdx3HHXgZMQKlAWlwyx57xpZBU2g ++qksO+KCLVYOQMN9usmuMOpHHAgMBAAGjgaEwgZ4wHQYDVR0eAQH/BBMwEaAPMA2C ++C2V4YW1wbGUuY29tMB0GA1UdDgQWBBR3T9IilPeRAFfLO8ocg216OBo+6DBDBgNV ++HSMEPDA6gBR3T9IilPeRAFfLO8ocg216OBo+6KEXpBUwEzERMA8GA1UEAwwITGVl ++dmlDQTSCCQCcfzY0+AuL4jAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjANBgkq ++hkiG9w0BAQsFAAOCAQEAR086ciNM3ujSQNhhguqFHYGfDRRuAgOk4l7GXIfFa9te ++B2KMLSwP367QaMwFxRrOoDvixIjzbpiiKB3cv+IXqGyfsRJw47XLwGK4FtSsXjst ++m2M8W5iXBQ94XoLj9OKb4ZJWKI930S/PF7uuxICtWttYSoylfyMkiR45+1SLj2eF ++X4EnXK3Q0H42v8LCDFqj9iNQ2WMLwA7kFPB+oOZxkFi2G0F3VuW+JZeBPQCpYdRO ++0kQQ/gIZE6KEdscKHi9y6OfGSeRlDBMADky9NiZy7I3AcspLcmMQh/191/DnooNe ++OwQ6w1HweApjB46bGyILpGUi9MZhvCnoLWg+cN3/wQ== ++-----END CERTIFICATE----- +diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data +index 0fe68cb06..e39f065e2 100644 +--- a/tests/suites/test_suite_x509parse.data ++++ b/tests/suites/test_suite_x509parse.data +@@ -1798,6 +1798,12 @@ X509 File parse (trailing spaces, OK) + depends_on:MBEDTLS_ECDSA_C:MBEDTLS_ECP_DP_SECP256R1_ENABLED:MBEDTLS_SHA256_C:MBEDTLS_RSA_C + x509parse_crt_file:"data_files/server7_trailing_space.crt":0 + ++X509 File parse (unsupported critical ext Name Constraints, fail) ++x509parse_crt_file:"data_files/test-ca-nc.crt":MBEDTLS_ERR_X509_INVALID_EXTENSIONS + MBEDTLS_ERR_ASN1_UNEXPECTED_TAG ++ ++X509 File parse (allowed unsupported critical ext Name Constraints, ok) ++x509parse_crt_file_allow_exts:"data_files/test-ca-nc.crt":MBEDTLS_X509_EXT_NAME_CONSTRAINTS:0 ++ + X509 Get time (UTC no issues) + depends_on:MBEDTLS_X509_USE_C + x509_get_time:MBEDTLS_ASN1_UTC_TIME:"500101000000Z":0:1950:1:1:0:0:0 +diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function +index 584ee822b..c12a0e0ef 100644 +--- a/tests/suites/test_suite_x509parse.function ++++ b/tests/suites/test_suite_x509parse.function +@@ -448,6 +448,21 @@ exit: + } + /* END_CASE */ + ++/* BEGIN_CASE depends_on:MBEDTLS_X509_CRT_PARSE_C:MBEDTLS_FS_IO */ ++void x509parse_crt_file_allow_exts( char *crt_file, int exts, int result ) ++{ ++ mbedtls_x509_crt crt; ++ ++ mbedtls_x509_crt_init( &crt ); ++ crt.allowed_unsupported_critical_exts = exts; ++ ++ TEST_ASSERT( mbedtls_x509_crt_parse_file( &crt, crt_file ) == result ); ++ ++exit: ++ mbedtls_x509_crt_free( &crt ); ++} ++/* END_CASE */ ++ + /* BEGIN_CASE depends_on:MBEDTLS_X509_CRT_PARSE_C */ + void x509parse_crt( char *crt_data, char *result_str, int result ) + { +-- +2.22.0.windows.1 + diff --git a/deps/mbedtls/patches/0003-fix-gcc-android-build.patch b/deps/mbedtls/patches/0003-fix-gcc-android-build.patch new file mode 100644 index 0000000..251de7b --- /dev/null +++ b/deps/mbedtls/patches/0003-fix-gcc-android-build.patch @@ -0,0 +1,13 @@ +Only in mbedtls-2.7.5/include/mbedtls: #bn_mul.h# +diff -ur mbedtls-2.7.5/include/mbedtls/bn_mul.h mbedtls-2.7.5.patch/include/mbedtls/bn_mul.h +--- mbedtls-2.7.5/include/mbedtls/bn_mul.h 2018-07-26 15:33:14.000000000 +0200 ++++ mbedtls-2.7.5.patch/include/mbedtls/bn_mul.h 2018-08-22 14:37:31.000000000 +0200 +@@ -56,7 +56,7 @@ + * This is done as the number of registers used in the assembly code doesn't + * work with the -O0 option. + */ +-#if defined(__i386__) && defined(__OPTIMIZE__) ++#if defined(__i386__) && defined(__OPTIMIZE__) && (!defined(__ANDROID_API__) || defined(__clang__)) + + #define MULADDC_INIT \ + asm( \ diff --git a/deps/minicrypto/aes-armv4.pl.patch b/deps/minicrypto/aes-armv4.pl.patch new file mode 100644 index 0000000..8578ec9 --- /dev/null +++ b/deps/minicrypto/aes-armv4.pl.patch @@ -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... diff --git a/deps/minicrypto/arm-as-to-ios b/deps/minicrypto/arm-as-to-ios new file mode 100755 index 0000000..0fe6d06 --- /dev/null +++ b/deps/minicrypto/arm-as-to-ios @@ -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() diff --git a/deps/minicrypto/arm-as-to-ios.orig b/deps/minicrypto/arm-as-to-ios.orig new file mode 100755 index 0000000..a049bca --- /dev/null +++ b/deps/minicrypto/arm-as-to-ios.orig @@ -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() diff --git a/deps/minicrypto/build-minicrypto b/deps/minicrypto/build-minicrypto new file mode 100755 index 0000000..f229b5d --- /dev/null +++ b/deps/minicrypto/build-minicrypto @@ -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 <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 diff --git a/deps/minicrypto/build-minicrypto-osx b/deps/minicrypto/build-minicrypto-osx new file mode 100755 index 0000000..5773833 --- /dev/null +++ b/deps/minicrypto/build-minicrypto-osx @@ -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 <=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 " + .align 2 +-.comm OPENSSL_armcap_P,4,4 + ___ + + $code =~ s/\`([^\`]*)\`/eval $1/gem; diff --git a/deps/openssl/build-openssl b/deps/openssl/build-openssl new file mode 100755 index 0000000..200dc6e --- /dev/null +++ b/deps/openssl/build-openssl @@ -0,0 +1,77 @@ +#!/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 + + +# source vars +. $O3/core/vars/vars-${TARGET} +. $O3/core/deps/lib-versions + +# source helper functions +. $O3/core/deps/functions.sh + +FNAME=openssl-${OPNESSL_VERSION}.tar.gz +URL=https://www.openssl.org/source/${OPENSSL_VERSION}.tar.gz +CSUM=${OPENSSL_CSUM} + +download + +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/$FNAME +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 diff --git a/deps/polarssl/.gitignore b/deps/polarssl/.gitignore new file mode 100644 index 0000000..75ea0b2 --- /dev/null +++ b/deps/polarssl/.gitignore @@ -0,0 +1 @@ +polartmp diff --git a/deps/polarssl/CMakeLists.txt b/deps/polarssl/CMakeLists.txt new file mode 100644 index 0000000..d98aca5 --- /dev/null +++ b/deps/polarssl/CMakeLists.txt @@ -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}) diff --git a/deps/polarssl/README.txt b/deps/polarssl/README.txt new file mode 100644 index 0000000..2c58a3d --- /dev/null +++ b/deps/polarssl/README.txt @@ -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 diff --git a/deps/polarssl/android.cmake b/deps/polarssl/android.cmake new file mode 100644 index 0000000..0f1d04f --- /dev/null +++ b/deps/polarssl/android.cmake @@ -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) diff --git a/deps/polarssl/apple.cmake b/deps/polarssl/apple.cmake new file mode 100644 index 0000000..2b58f24 --- /dev/null +++ b/deps/polarssl/apple.cmake @@ -0,0 +1,4 @@ +# specify the cross compiler +SET(CMAKE_C_COMPILER clang) +SET(CMAKE_CXX_COMPILER clang++) +SET(CMAKE_COMPILER_IS_GNUCC 1) diff --git a/deps/polarssl/bignum-arm.patch b/deps/polarssl/bignum-arm.patch new file mode 100644 index 0000000..12178ae --- /dev/null +++ b/deps/polarssl/bignum-arm.patch @@ -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; + diff --git a/deps/polarssl/build-detail-patch b/deps/polarssl/build-detail-patch new file mode 100755 index 0000000..a71e342 --- /dev/null +++ b/deps/polarssl/build-detail-patch @@ -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' diff --git a/deps/polarssl/build-mini-openssl b/deps/polarssl/build-mini-openssl new file mode 100755 index 0000000..6ecf736 --- /dev/null +++ b/deps/polarssl/build-mini-openssl @@ -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 " + 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 .. diff --git a/deps/polarssl/build-polarssl b/deps/polarssl/build-polarssl new file mode 100755 index 0000000..dad7a23 --- /dev/null +++ b/deps/polarssl/build-polarssl @@ -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 diff --git a/deps/polarssl/build-polarssl-patch b/deps/polarssl/build-polarssl-patch new file mode 100755 index 0000000..1562ac2 --- /dev/null +++ b/deps/polarssl/build-polarssl-patch @@ -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 diff --git a/deps/polarssl/config.h b/deps/polarssl/config.h new file mode 100644 index 0000000..482b3ed --- /dev/null +++ b/deps/polarssl/config.h @@ -0,0 +1,2227 @@ +/** + * \file config.h + * + * \brief Configuration options (set of defines) + * + * Copyright (C) 2006-2014, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * 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 + +#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(). + * + * Requires support for asm() in compiler. + * + * Used in: + * library/timing.c + * library/padlock.c + * include/polarssl/bn_mul.h + * + * Comment to disable the use of assembly code. + */ +#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 + +/** + * \def POLARSSL_HAVE_TIME + * + * System has time.h and time() / localtime() / gettimeofday(). + * + * Comment if your system does not support time functions + */ +#define POLARSSL_HAVE_TIME + +/** + * \def POLARSSL_HAVE_IPV6 + * + * System supports the basic socket interface for IPv6 (RFC 3493), + * specifically getaddrinfo(), freeaddrinfo() and struct sockaddr_storage. + * + * Note: on Windows/MingW, XP or higher is required. + * + * Comment if your system does not support the IPv6 socket interface + */ +#define POLARSSL_HAVE_IPV6 + +/** + * \def POLARSSL_PLATFORM_MEMORY + * + * Enable the memory allocation layer. + * + * By default PolarSSL uses the system-provided malloc() and free(). + * This allows different allocators (self-implemented or provided) to be + * provided to the platform abstraction layer. + * + * Enabling POLARSSL_PLATFORM_MEMORY will provide "platform_set_malloc_free()" + * to allow you to set an alternative malloc() and free() function pointer. + * + * Requires: POLARSSL_PLATFORM_C + * + * Enable this layer to allow use of alternative memory allocators. + */ +//#define POLARSSL_PLATFORM_MEMORY + +/** + * \def POLARSSL_PLATFORM_NO_STD_FUNCTIONS + * + * Do not assign standard functions in the platform layer (e.g. malloc() to + * POLARSSL_PLATFORM_STD_MALLOC and printf() to POLARSSL_PLATFORM_STD_PRINTF) + * + * This makes sure there are no linking errors on platforms that do not support + * these functions. You will HAVE to provide alternatives, either at runtime + * via the platform_set_xxx() functions or at compile time by setting + * the POLARSSL_PLATFORM_STD_XXX defines. + * + * Requires: POLARSSL_PLATFORM_C + * + * Uncomment to prevent default assignment of standard functions in the + * platform layer. + */ +//#define POLARSSL_PLATFORM_NO_STD_FUNCTIONS + +/** + * \def POLARSSL_PLATFORM_XXX_ALT + * + * Uncomment a macro to let PolarSSL support the function in the platform + * abstraction layer. + * + * Example: In case you uncomment POLARSSL_PLATFORM_PRINTF_ALT, PolarSSL will + * provide a function "platform_set_printf()" that allows you to set an + * alternative printf function pointer. + * + * All these define require POLARSSL_PLATFORM_C to be defined! + * + * Uncomment a macro to enable alternate implementation of specific base + * platform function + */ +//#define POLARSSL_PLATFORM_PRINTF_ALT +//#define POLARSSL_PLATFORM_FPRINTF_ALT +/* \} name SECTION: System support */ + +/** + * \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_TIMING_ALT + * + * Uncomment to provide your own alternate implementation for hardclock(), + * get_timer(), set_alarm() and m_sleep(). + * + * Only works if you have POLARSSL_TIMING_C enabled. + * + * You will need to provide a header "timing_alt.h" and an implementation at + * compile time. + */ +//#define POLARSSL_TIMING_ALT + +/** + * \def POLARSSL_XXX_ALT + * + * Uncomment a macro to let PolarSSL use your alternate core implementation of + * a symmetric or hash algorithm (e.g. platform specific assembly optimized + * implementations). Keep in mind that the function prototypes should remain + * the same. + * + * Example: In case you uncomment POLARSSL_AES_ALT, PolarSSL will no longer + * provide the "struct aes_context" definition and omit the base function + * declarations and implementations. "aes_alt.h" will be included from + * "aes.h" to include the new function definitions. + * + * Uncomment a macro to enable alternate implementation for core algorithm + * functions + */ +//#define POLARSSL_AES_ALT +//#define POLARSSL_ARC4_ALT +//#define POLARSSL_BLOWFISH_ALT +//#define POLARSSL_CAMELLIA_ALT +//#define POLARSSL_DES_ALT +//#define POLARSSL_XTEA_ALT +//#define POLARSSL_MD2_ALT +//#define POLARSSL_MD4_ALT +//#define POLARSSL_MD5_ALT +//#define POLARSSL_RIPEMD160_ALT +//#define POLARSSL_SHA1_ALT +//#define POLARSSL_SHA256_ALT +//#define POLARSSL_SHA512_ALT + +/** + * \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_CBC + * + * Enable Cipher Block Chaining mode (CBC) for symmetric ciphers. + */ +#define POLARSSL_CIPHER_MODE_CBC + +/** + * \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. + */ +#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_ECDH_ECDSA_WITH_NULL_SHA + * TLS_ECDH_RSA_WITH_NULL_SHA + * TLS_ECDHE_ECDSA_WITH_NULL_SHA + * TLS_ECDHE_RSA_WITH_NULL_SHA + * TLS_ECDHE_PSK_WITH_NULL_SHA384 + * TLS_ECDHE_PSK_WITH_NULL_SHA256 + * TLS_ECDHE_PSK_WITH_NULL_SHA + * TLS_DHE_PSK_WITH_NULL_SHA384 + * TLS_DHE_PSK_WITH_NULL_SHA256 + * TLS_DHE_PSK_WITH_NULL_SHA + * TLS_RSA_WITH_NULL_SHA256 + * TLS_RSA_WITH_NULL_SHA + * TLS_RSA_WITH_NULL_MD5 + * TLS_RSA_PSK_WITH_NULL_SHA384 + * TLS_RSA_PSK_WITH_NULL_SHA256 + * TLS_RSA_PSK_WITH_NULL_SHA + * TLS_PSK_WITH_NULL_SHA384 + * TLS_PSK_WITH_NULL_SHA256 + * TLS_PSK_WITH_NULL_SHA + * + * Uncomment this macro to enable the NULL cipher and ciphersuites + */ +//#define POLARSSL_CIPHER_NULL_CIPHER + +/** + * \def POLARSSL_CIPHER_PADDING_XXX + * + * Uncomment or comment macros to add support for specific padding modes + * in the cipher layer with cipher modes that support padding (e.g. CBC) + * + * If you disable all padding modes, only full blocks can be used with CBC. + * + * Enable padding modes in the cipher layer. + */ +#define POLARSSL_CIPHER_PADDING_PKCS7 +#define POLARSSL_CIPHER_PADDING_ONE_AND_ZEROS +#define POLARSSL_CIPHER_PADDING_ZEROS_AND_LEN +#define POLARSSL_CIPHER_PADDING_ZEROS + +/** + * \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_REMOVE_ARC4_CIPHERSUITES + * + * Remove RC4 ciphersuites by default in SSL / TLS. + * This flag removes the ciphersuites based on RC4 from the default list as + * returned by ssl_list_ciphersuites(). However, it is still possible to + * enable (some of) them with ssl_set_ciphersuites() by including them + * explicitly. + * + * Uncomment this macro to remove RC4 ciphersuites by default. + */ +// JY added -- crypto +#define POLARSSL_REMOVE_ARC4_CIPHERSUITES + +/** + * \def POLARSSL_ECP_XXXX_ENABLED + * + * Enables specific curves within the Elliptic Curve module. + * By default all supported curves are enabled. + * + * Comment macros to disable the curve and functions for it + */ +#define POLARSSL_ECP_DP_SECP192R1_ENABLED +#define POLARSSL_ECP_DP_SECP224R1_ENABLED +#define POLARSSL_ECP_DP_SECP256R1_ENABLED +#define POLARSSL_ECP_DP_SECP384R1_ENABLED +#define POLARSSL_ECP_DP_SECP521R1_ENABLED +#define POLARSSL_ECP_DP_SECP192K1_ENABLED +#define POLARSSL_ECP_DP_SECP224K1_ENABLED +#define POLARSSL_ECP_DP_SECP256K1_ENABLED +#define POLARSSL_ECP_DP_BP256R1_ENABLED +#define POLARSSL_ECP_DP_BP384R1_ENABLED +#define POLARSSL_ECP_DP_BP512R1_ENABLED +//#define POLARSSL_ECP_DP_M221_ENABLED // Not implemented yet! +#define POLARSSL_ECP_DP_M255_ENABLED +//#define POLARSSL_ECP_DP_M383_ENABLED // Not implemented yet! +//#define POLARSSL_ECP_DP_M511_ENABLED // Not implemented yet! + +/** + * \def POLARSSL_ECP_NIST_OPTIM + * + * Enable specific 'modulo p' routines for each NIST prime. + * Depending on the prime and architecture, makes operations 4 to 8 times + * faster on the corresponding curve. + * + * Comment this macro to disable NIST curves optimisation. + */ +#define POLARSSL_ECP_NIST_OPTIM + +/** + * \def POLARSSL_ECDSA_DETERMINISTIC + * + * Enable deterministic ECDSA (RFC 6979). + * Standard ECDSA is "fragile" in the sense that lack of entropy when signing + * may result in a compromise of the long-term signing key. This is avoided by + * the deterministic variant. + * + * Requires: POLARSSL_HMAC_DRBG_C + * + * Comment this macro to disable deterministic ECDSA. + */ +#define POLARSSL_ECDSA_DETERMINISTIC + +/** + * \def POLARSSL_KEY_EXCHANGE_PSK_ENABLED + * + * Enable the PSK based ciphersuite modes in SSL / TLS. + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_PSK_WITH_AES_256_GCM_SHA384 + * TLS_PSK_WITH_AES_256_CBC_SHA384 + * TLS_PSK_WITH_AES_256_CBC_SHA + * TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_PSK_WITH_AES_128_GCM_SHA256 + * TLS_PSK_WITH_AES_128_CBC_SHA256 + * TLS_PSK_WITH_AES_128_CBC_SHA + * TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_PSK_WITH_3DES_EDE_CBC_SHA + * TLS_PSK_WITH_RC4_128_SHA + */ +// JY removed -- PSK +//#define POLARSSL_KEY_EXCHANGE_PSK_ENABLED + +/** + * \def POLARSSL_KEY_EXCHANGE_DHE_PSK_ENABLED + * + * Enable the DHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: POLARSSL_DHM_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * TLS_DHE_PSK_WITH_AES_128_CBC_SHA + * TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA + * TLS_DHE_PSK_WITH_RC4_128_SHA + */ +// JY removed -- PSK +//#define POLARSSL_KEY_EXCHANGE_DHE_PSK_ENABLED + +/** + * \def POLARSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED + * + * Enable the ECDHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: POLARSSL_ECDH_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + * TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + * TLS_ECDHE_PSK_WITH_RC4_128_SHA + */ +// JY removed -- PSK +//#define POLARSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED + +/** + * \def POLARSSL_KEY_EXCHANGE_RSA_PSK_ENABLED + * + * Enable the RSA-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: POLARSSL_RSA_C, POLARSSL_PKCS1_V15, + * POLARSSL_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * TLS_RSA_PSK_WITH_AES_128_CBC_SHA + * TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA + * TLS_RSA_PSK_WITH_RC4_128_SHA + */ +// JY removed -- PSK +//#define POLARSSL_KEY_EXCHANGE_RSA_PSK_ENABLED + +/** + * \def POLARSSL_KEY_EXCHANGE_RSA_ENABLED + * + * Enable the RSA-only based ciphersuite modes in SSL / TLS. + * + * Requires: POLARSSL_RSA_C, POLARSSL_PKCS1_V15, + * POLARSSL_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_RSA_WITH_AES_256_GCM_SHA384 + * TLS_RSA_WITH_AES_256_CBC_SHA256 + * TLS_RSA_WITH_AES_256_CBC_SHA + * TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + * TLS_RSA_WITH_AES_128_GCM_SHA256 + * TLS_RSA_WITH_AES_128_CBC_SHA256 + * TLS_RSA_WITH_AES_128_CBC_SHA + * TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + * TLS_RSA_WITH_3DES_EDE_CBC_SHA + * TLS_RSA_WITH_RC4_128_SHA + * TLS_RSA_WITH_RC4_128_MD5 + */ +#define POLARSSL_KEY_EXCHANGE_RSA_ENABLED + +/** + * \def POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED + * + * Enable the DHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: POLARSSL_DHM_C, POLARSSL_RSA_C, POLARSSL_PKCS1_V15, + * POLARSSL_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + */ +#define POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED + +/** + * \def POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED + * + * Enable the ECDHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: POLARSSL_ECDH_C, POLARSSL_RSA_C, POLARSSL_PKCS1_V15, + * POLARSSL_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + * TLS_ECDHE_RSA_WITH_RC4_128_SHA + */ +#define POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED + +/** + * \def POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + * + * Enable the ECDHE-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: POLARSSL_ECDH_C, POLARSSL_ECDSA_C, POLARSSL_X509_CRT_PARSE_C, + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + * TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + */ +#define POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +/** + * \def POLARSSL_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + * + * Enable the ECDH-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: POLARSSL_ECDH_C, POLARSSL_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + * TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + */ +#define POLARSSL_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + +/** + * \def POLARSSL_KEY_EXCHANGE_ECDH_RSA_ENABLED + * + * Enable the ECDH-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: POLARSSL_ECDH_C, POLARSSL_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_ECDH_RSA_WITH_RC4_128_SHA + * TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + * TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + */ +#define POLARSSL_KEY_EXCHANGE_ECDH_RSA_ENABLED + +/** + * \def POLARSSL_PK_PARSE_EC_EXTENDED + * + * Enhance support for reading EC keys using variants of SEC1 not allowed by + * RFC 5915 and RFC 5480. + * + * Currently this means parsing the SpecifiedECDomain choice of EC + * parameters (only known groups are supported, not arbitrary domains, to + * avoid validation issues). + * + * Disable if you only need to support RFC 5915 + 5480 key formats. + */ +#define POLARSSL_PK_PARSE_EC_EXTENDED + +/** + * \def POLARSSL_ERROR_STRERROR_BC + * + * Make available the backward compatible error_strerror() next to the + * current polarssl_strerror(). + * + * For new code, it is recommended to use polarssl_strerror() instead and + * disable this. + * + * Disable if you run into name conflicts and want to really remove the + * error_strerror() + */ +// JY removed +//#define POLARSSL_ERROR_STRERROR_BC + +/** + * \def POLARSSL_ERROR_STRERROR_DUMMY + * + * Enable a dummy error function to make use of polarssl_strerror() in + * third party libraries easier when POLARSSL_ERROR_C is disabled + * (no effect when POLARSSL_ERROR_C is enabled). + * + * You can safely disable this if POLARSSL_ERROR_C is enabled, or if you're + * not using polarssl_strerror() or error_strerror() in your application. + * + * Disable if you run into name conflicts and want to really remove the + * polarssl_strerror() + */ +#define POLARSSL_ERROR_STRERROR_DUMMY + +/** + * \def POLARSSL_GENPRIME + * + * Enable the prime-number generation code. + * + * Requires: POLARSSL_BIGNUM_C + */ +#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_ENTROPY_FORCE_SHA256 + * + * Force the entropy accumulator to use a SHA-256 accumulator instead of the + * default SHA-512 based one (if both are available). + * + * Requires: POLARSSL_SHA256_C + * + * On 32-bit systems SHA-256 can be much faster than SHA-512. Use this option + * if you have performance concerns. + * + * This option is only useful if both POLARSSL_SHA256_C and + * POLARSSL_SHA512_C are defined. Otherwise the available hash module is used. + */ +//#define POLARSSL_ENTROPY_FORCE_SHA256 + +/** + * \def POLARSSL_MEMORY_DEBUG + * + * Enable debugging of buffer allocator memory issues. Automatically prints + * (to stderr) all (fatal) messages on memory allocation issues. Enables + * function for 'debug output' of allocated memory. + * + * Requires: POLARSSL_MEMORY_BUFFER_ALLOC_C + * + * Uncomment this macro to let the buffer allocator print out error messages. + */ +//#define POLARSSL_MEMORY_DEBUG + +/** + * \def POLARSSL_MEMORY_BACKTRACE + * + * Include backtrace information with each allocated block. + * + * Requires: POLARSSL_MEMORY_BUFFER_ALLOC_C + * GLIBC-compatible backtrace() an backtrace_symbols() support + * + * Uncomment this macro to include backtrace information + */ +//#define POLARSSL_MEMORY_BACKTRACE + +/** + * \def POLARSSL_PKCS1_V15 + * + * Enable support for PKCS#1 v1.5 encoding. + * + * Requires: POLARSSL_RSA_C + * + * This enables support for PKCS#1 v1.5 operations. + */ +#define POLARSSL_PKCS1_V15 + +/** + * \def POLARSSL_PKCS1_V21 + * + * Enable support for PKCS#1 v2.1 encoding. + * + * Requires: POLARSSL_MD_C, POLARSSL_RSA_C + * + * 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_SSL_SRV_RESPECT_CLIENT_PREFERENCE + * + * Pick the ciphersuite according to the client's preferences rather than ours + * in the SSL Server module (POLARSSL_SSL_SRV_C). + * + * Uncomment this macro to respect client's ciphersuite order + */ +//#define POLARSSL_SSL_SRV_RESPECT_CLIENT_PREFERENCE + +/** + * \def POLARSSL_SSL_MAX_FRAGMENT_LENGTH + * + * Enable support for RFC 6066 max_fragment_length extension in SSL. + * + * Comment this macro to disable support for the max_fragment_length extension + */ +#define POLARSSL_SSL_MAX_FRAGMENT_LENGTH + +/** + * \def POLARSSL_SSL_PROTO_SSL3 + * + * Enable support for SSL 3.0. + * + * Requires: POLARSSL_MD5_C + * POLARSSL_SHA1_C + * + * Comment this macro to disable support for SSL 3.0 + */ +#define POLARSSL_SSL_PROTO_SSL3 + +/** + * \def POLARSSL_SSL_PROTO_TLS1 + * + * Enable support for TLS 1.0. + * + * Requires: POLARSSL_MD5_C + * POLARSSL_SHA1_C + * + * Comment this macro to disable support for TLS 1.0 + */ +#define POLARSSL_SSL_PROTO_TLS1 + +/** + * \def POLARSSL_SSL_PROTO_TLS1_1 + * + * Enable support for TLS 1.1. + * + * Requires: POLARSSL_MD5_C + * POLARSSL_SHA1_C + * + * Comment this macro to disable support for TLS 1.1 + */ +#define POLARSSL_SSL_PROTO_TLS1_1 + +/** + * \def POLARSSL_SSL_PROTO_TLS1_2 + * + * Enable support for TLS 1.2. + * + * Requires: POLARSSL_SHA1_C or POLARSSL_SHA256_C or POLARSSL_SHA512_C + * (Depends on ciphersuites) + * + * Comment this macro to disable support for TLS 1.2 + */ +#define POLARSSL_SSL_PROTO_TLS1_2 + +/** + * \def POLARSSL_SSL_ALPN + * + * Enable support for Application Layer Protocol Negotiation. + * draft-ietf-tls-applayerprotoneg-05 + * + * Comment this macro to disable support for ALPN. + */ +#define POLARSSL_SSL_ALPN + +/** + * \def POLARSSL_SSL_SESSION_TICKETS + * + * Enable support for RFC 5077 session tickets in SSL. + * + * Requires: POLARSSL_AES_C + * POLARSSL_SHA256_C + * POLARSSL_CIPHER_MODE_CBC + * + * Comment this macro to disable support for SSL session tickets + */ +// JY removed +//#define POLARSSL_SSL_SESSION_TICKETS + +/** + * \def POLARSSL_SSL_SERVER_NAME_INDICATION + * + * Enable support for RFC 6066 server name indication (SNI) in SSL. + * + * Comment this macro to disable support for server name indication in SSL + */ +#define POLARSSL_SSL_SERVER_NAME_INDICATION + +/** + * \def POLARSSL_SSL_TRUNCATED_HMAC + * + * Enable support for RFC 6066 truncated HMAC in SSL. + * + * Comment this macro to disable support for truncated HMAC in SSL + */ +#define POLARSSL_SSL_TRUNCATED_HMAC + +/** + * \def POLARSSL_SSL_SET_CURVES + * + * Enable ssl_set_curves(). + * + * This is disabled by default since it breaks binary compatibility with the + * 1.3.x line. If you choose to enable it, you will need to rebuild your + * application against the new header files, relinking will not be enough. + * It will be enabled by default, or no longer an option, in the 1.4 branch. + * + * Uncomment to make ssl_set_curves() available. + */ +//#define POLARSSL_SSL_SET_CURVES + +/** + * \def POLARSSL_THREADING_ALT + * + * Provide your own alternate threading implementation. + * + * Requires: POLARSSL_THREADING_C + * + * Uncomment this to allow your own alternate threading implementation. + */ +//#define POLARSSL_THREADING_ALT + +/** + * \def POLARSSL_THREADING_PTHREAD + * + * Enable the pthread wrapper layer for the threading layer. + * + * Requires: POLARSSL_THREADING_C + * + * Uncomment this to enable pthread mutexes. + */ +//#define POLARSSL_THREADING_PTHREAD + +/** + * \def POLARSSL_VERSION_FEATURES + * + * Allow run-time checking of compile-time enabled features. Thus allowing users + * to check at run-time if the library is for instance compiled with threading + * support via version_check_feature(). + * + * Requires: POLARSSL_VERSION_C + * + * Comment this to disable run-time checking and save ROM space + */ +#define POLARSSL_VERSION_FEATURES + +/** + * \def POLARSSL_X509_ALLOW_EXTENSIONS_NON_V3 + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering an extension in a v1 or v2 certificate. + * + * Uncomment to prevent an error. + */ +// JY Added +#define POLARSSL_X509_ALLOW_EXTENSIONS_NON_V3 + +/** + * \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. + */ +// JY Added +#define POLARSSL_X509_ALLOW_UNSUPPORTED_CRITICAL_EXTENSION + +/** + * \def POLARSSL_X509_CHECK_KEY_USAGE + * + * Enable verification of the keyUsage extension (CA and leaf certificates). + * + * Disabling this avoids problems with mis-issued and/or misused + * (intermediate) CA and leaf certificates. + * + * \warning Depending on your PKI use, disabling this can be a security risk! + * + * Comment to skip keyUsage checking for both CA and leaf certificates. + */ +#define POLARSSL_X509_CHECK_KEY_USAGE + +/** + * \def POLARSSL_X509_CHECK_EXTENDED_KEY_USAGE + * + * Enable verification of the extendedKeyUsage extension (leaf certificates). + * + * Disabling this avoids problems with mis-issued and/or misused certificates. + * + * \warning Depending on your PKI use, disabling this can be a security risk! + * + * Comment to skip extendedKeyUsage checking for certificates. + */ +#define POLARSSL_X509_CHECK_EXTENDED_KEY_USAGE + +/** + * \def POLARSSL_X509_RSASSA_PSS_SUPPORT + * + * Enable parsing and verification of X.509 certificates, CRLs and CSRS + * signed with RSASSA-PSS (aka PKCS#1 v2.1). + * + * Comment this macro to disallow using RSASSA-PSS in certificates. + */ +#define POLARSSL_X509_RSASSA_PSS_SUPPORT + +/** + * \def POLARSSL_ZLIB_SUPPORT + * + * If set, the SSL/TLS module uses ZLIB to support compression and + * decompression of packet data. + * + * \warning TLS-level compression MAY REDUCE SECURITY! See for example the + * CRIME attack. Before enabling this option, you should examine with care if + * CRIME or similar exploits may be a applicable to your use case. + * + * 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 SECTION: PolarSSL feature support */ + +/** + * \name SECTION: PolarSSL modules + * + * This section enables or disables entire modules in PolarSSL + * \{ + */ + +/** + * \def POLARSSL_AESNI_C + * + * Enable AES-NI support on x86-64. + * + * Module: library/aesni.c + * Caller: library/aes.c + * + * Requires: POLARSSL_HAVE_ASM + * + * This modules adds support for the AES-NI instructions on x86-64 + */ +// JY added +#ifndef POLARSSL_AES_ALT +#define POLARSSL_AESNI_C +#endif + +/** + * \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_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + * TLS_DHE_PSK_WITH_AES_128_CBC_SHA + * TLS_RSA_WITH_AES_256_GCM_SHA384 + * TLS_RSA_WITH_AES_256_CBC_SHA256 + * TLS_RSA_WITH_AES_256_CBC_SHA + * TLS_RSA_WITH_AES_128_GCM_SHA256 + * TLS_RSA_WITH_AES_128_CBC_SHA256 + * TLS_RSA_WITH_AES_128_CBC_SHA + * TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * TLS_RSA_PSK_WITH_AES_128_CBC_SHA + * TLS_PSK_WITH_AES_256_GCM_SHA384 + * TLS_PSK_WITH_AES_256_CBC_SHA384 + * TLS_PSK_WITH_AES_256_CBC_SHA + * TLS_PSK_WITH_AES_128_GCM_SHA256 + * TLS_PSK_WITH_AES_128_CBC_SHA256 + * TLS_PSK_WITH_AES_128_CBC_SHA + * + * PEM_PARSE 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 (if other requisites are + * enabled as well): + * TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * TLS_ECDH_RSA_WITH_RC4_128_SHA + * TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + * TLS_ECDHE_RSA_WITH_RC4_128_SHA + * TLS_ECDHE_PSK_WITH_RC4_128_SHA + * TLS_DHE_PSK_WITH_RC4_128_SHA + * TLS_RSA_WITH_RC4_128_SHA + * TLS_RSA_WITH_RC4_128_MD5 + * TLS_RSA_PSK_WITH_RC4_128_SHA + * TLS_PSK_WITH_RC4_128_SHA + */ +// JY removed -- crypto +//#define POLARSSL_ARC4_C + +/** + * \def POLARSSL_ASN1_PARSE_C + * + * Enable the generic ASN1 parser. + * + * Module: library/asn1.c + * Caller: library/x509.c + * library/dhm.c + * library/pkcs12.c + * library/pkcs5.c + * library/pkparse.c + */ +#define POLARSSL_ASN1_PARSE_C + +/** + * \def POLARSSL_ASN1_WRITE_C + * + * Enable the generic ASN1 writer. + * + * Module: library/asn1write.c + * Caller: library/ecdsa.c + * library/pkwrite.c + * library/x509_create.c + * library/x509write_crt.c + * library/x509write_csr.c + */ +#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/ecp.c + * library/ecdsa.c + * library/rsa.c + * library/ssl_tls.c + * + * This module is required for RSA, DHM and ECC (ECDH, ECDSA) 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_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + * TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + * TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 + */ +// JY removed -- crypto +//#define POLARSSL_CAMELLIA_C + +/** + * \def POLARSSL_CCM_C + * + * Enable the Counter with CBC-MAC (CCM) mode for 128-bit block cipher. + * + * Module: library/ccm.c + * + * Requires: POLARSSL_AES_C or POLARSSL_CAMELLIA_C + * + * This module enables the AES-CCM ciphersuites, if other requisites are + * enabled as well. + */ +#define POLARSSL_CCM_C + +/** + * \def POLARSSL_CERTS_C + * + * Enable the test certificates. + * + * Module: library/certs.c + * Caller: + * + * Requires: POLARSSL_PEM_PARSE_C + * + * 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: library/ssl_tls.c + * + * 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_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + * TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + * TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + * TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + * TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + * TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + * TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA + * TLS_RSA_WITH_3DES_EDE_CBC_SHA + * TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA + * TLS_PSK_WITH_3DES_EDE_CBC_SHA + * + * PEM_PARSE uses DES/3DES for decrypting encrypted keys. + */ +#define POLARSSL_DES_C + +/** + * \def POLARSSL_DHM_C + * + * Enable the Diffie-Hellman-Merkle module. + * + * Module: library/dhm.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * DHE-RSA, DHE-PSK + */ +#define POLARSSL_DHM_C + +/** + * \def POLARSSL_ECDH_C + * + * Enable the elliptic curve Diffie-Hellman library. + * + * Module: library/ecdh.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA, ECDHE-RSA, DHE-PSK + * + * Requires: POLARSSL_ECP_C + */ +#define POLARSSL_ECDH_C + +/** + * \def POLARSSL_ECDSA_C + * + * Enable the elliptic curve DSA library. + * + * Module: library/ecdsa.c + * Caller: + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA + * + * Requires: POLARSSL_ECP_C, POLARSSL_ASN1_WRITE_C, POLARSSL_ASN1_PARSE_C + */ +#define POLARSSL_ECDSA_C + +/** + * \def POLARSSL_ECP_C + * + * Enable the elliptic curve over GF(p) library. + * + * Module: library/ecp.c + * Caller: library/ecdh.c + * library/ecdsa.c + * + * Requires: POLARSSL_BIGNUM_C and at least one POLARSSL_ECP_DP_XXX_ENABLED + */ +#define POLARSSL_ECP_C + +/** + * \def POLARSSL_ENTROPY_C + * + * Enable the platform-specific entropy code. + * + * Module: library/entropy.c + * Caller: + * + * Requires: POLARSSL_SHA512_C or POLARSSL_SHA256_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 polarssl_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 or POLARSSL_CAMELLIA_C + * + * This module enables the AES-GCM and CAMELLIA-GCM ciphersuites, if other + * requisites are enabled as well. + */ +#define POLARSSL_GCM_C + +/** + * \def POLARSSL_HAVEGE_C + * + * Enable the HAVEGE random generator. + * + * Warning: the HAVEGE random generator is not suitable for virtualized + * environments + * + * Warning: the HAVEGE random generator is dependent on timing and specific + * processor traits. It is therefore not advised to use HAVEGE as + * your applications primary random generator or primary entropy pool + * input. As a secondary input to your entropy pool, it IS able add + * the (limited) extra entropy it provides. + * + * Module: library/havege.c + * Caller: + * + * Requires: POLARSSL_TIMING_C + * + * Uncomment to enable the HAVEGE random generator. + */ +//#define POLARSSL_HAVEGE_C + +/** + * \def POLARSSL_HMAC_DRBG_C + * + * Enable the HMAC_DRBG random generator. + * + * Module: library/hmac_drbg.c + * Caller: + * + * Requires: POLARSSL_MD_C + * + * Uncomment to enable the HMAC_DRBG random number geerator. + */ +#define POLARSSL_HMAC_DRBG_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: + * + * 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: + * + * 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/md.c + * library/pem.c + * library/ssl_tls.c + * + * This module is required for SSL/TLS and X.509. + * PEM_PARSE uses MD5 for decrypting encrypted keys. + */ +#define POLARSSL_MD5_C + +/** + * \def POLARSSL_MEMORY_C + * Deprecated since 1.3.5. Please use POLARSSL_PLATFORM_MEMORY instead. + */ +//#define POLARSSL_MEMORY_C + +/** + * \def POLARSSL_MEMORY_BUFFER_ALLOC_C + * + * Enable the buffer allocator implementation that makes use of a (stack) + * based buffer to 'allocate' dynamic memory. (replaces malloc() and free() + * calls) + * + * Module: library/memory_buffer_alloc.c + * + * Requires: POLARSSL_PLATFORM_C + * POLARSSL_PLATFORM_MEMORY (to use it within PolarSSL) + * + * Enable this module to enable the buffer memory allocator. + */ +//#define POLARSSL_MEMORY_BUFFER_ALLOC_C + +/** + * \def POLARSSL_NET_C + * + * Enable the TCP/IP networking routines. + * + * Module: library/net.c + * + * This module provides TCP/IP networking routines. + */ +// JY removed +//#define POLARSSL_NET_C + +/** + * \def POLARSSL_OID_C + * + * Enable the OID database. + * + * Module: library/oid.c + * Caller: library/asn1write.c + * library/pkcs5.c + * library/pkparse.c + * library/pkwrite.c + * library/rsa.c + * library/x509.c + * library/x509_create.c + * library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c + * library/x509write_crt.c + * library/x509write_csr.c + * + * This modules translates between OIDs and internal values. + */ +#define POLARSSL_OID_C + +/** + * \def POLARSSL_PADLOCK_C + * + * Enable VIA Padlock support on x86. + * + * Module: library/padlock.c + * Caller: library/aes.c + * + * Requires: POLARSSL_HAVE_ASM + * + * 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_PARSE_C + * + * Enable PEM decoding / parsing. + * + * Module: library/pem.c + * Caller: library/dhm.c + * library/pkparse.c + * library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c + * + * Requires: POLARSSL_BASE64_C + * + * This modules adds support for decoding / parsing PEM files. + */ +#define POLARSSL_PEM_PARSE_C + +/** + * \def POLARSSL_PEM_WRITE_C + * + * Enable PEM encoding / writing. + * + * Module: library/pem.c + * Caller: library/pkwrite.c + * library/x509write_crt.c + * library/x509write_csr.c + * + * Requires: POLARSSL_BASE64_C + * + * This modules adds support for encoding / writing PEM files. + */ +#define POLARSSL_PEM_WRITE_C + +/** + * \def POLARSSL_PK_C + * + * Enable the generic public (asymetric) key layer. + * + * Module: library/pk.c + * Caller: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: POLARSSL_RSA_C or POLARSSL_ECP_C + * + * Uncomment to enable generic public key wrappers. + */ +#define POLARSSL_PK_C + +/** + * \def POLARSSL_PK_PARSE_C + * + * Enable the generic public (asymetric) key parser. + * + * Module: library/pkparse.c + * Caller: library/x509_crt.c + * library/x509_csr.c + * + * Requires: POLARSSL_PK_C + * + * Uncomment to enable generic public key parse functions. + */ +#define POLARSSL_PK_PARSE_C + +/** + * \def POLARSSL_PK_WRITE_C + * + * Enable the generic public (asymetric) key writer. + * + * Module: library/pkwrite.c + * Caller: library/x509write.c + * + * Requires: POLARSSL_PK_C + * + * Uncomment to enable generic public key write functions. + */ +// JY removed -- PKI +//#define POLARSSL_PK_WRITE_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/pkcs11.c + * Caller: library/pk.c + * + * Requires: POLARSSL_PK_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/pkparse.c + * + * Requires: POLARSSL_ASN1_PARSE_C, POLARSSL_CIPHER_C, POLARSSL_MD_C + * Can use: POLARSSL_ARC4_C + * + * This module enables PKCS#12 functions. + */ +#define POLARSSL_PKCS12_C + +/** + * \def POLARSSL_PLATFORM_C + * + * Enable the platform abstraction layer that allows you to re-assign + * functions like malloc(), free(), printf(), fprintf() + * + * Module: library/platform.c + * Caller: Most other .c files + * + * This module enables abstraction of common (libc) functions. + */ +#define POLARSSL_PLATFORM_C + +/** + * \def POLARSSL_RIPEMD160_C + * + * Enable the RIPEMD-160 hash algorithm. + * + * Module: library/ripemd160.c + * Caller: library/md.c + * + */ +// JY removed +//#define POLARSSL_RIPEMD160_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 + * + * This module is used by the following key exchanges: + * RSA, DHE-RSA, ECDHE-RSA, RSA-PSK + * + * Requires: POLARSSL_BIGNUM_C, POLARSSL_OID_C + */ +#define POLARSSL_RSA_C + +/** + * \def POLARSSL_SHA1_C + * + * Enable the SHA1 cryptographic hash algorithm. + * + * Module: library/sha1.c + * Caller: library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509write_crt.c + * + * This module is required for SSL/TLS and SHA1-signed certificates. + */ +#define POLARSSL_SHA1_C + +/** + * \def POLARSSL_SHA256_C + * + * Enable the SHA-224 and SHA-256 cryptographic hash algorithms. + * (Used to be POLARSSL_SHA2_C) + * + * Module: library/sha256.c + * Caller: library/entropy.c + * library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.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_SHA256_C + +/** + * \def POLARSSL_SHA512_C + * + * Enable the SHA-384 and SHA-512 cryptographic hash algorithms. + * (Used to be POLARSSL_SHA4_C) + * + * Module: library/sha512.c + * Caller: library/entropy.c + * library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * This module adds support for SHA-384 and SHA-512. + */ +#define POLARSSL_SHA512_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 -- server +//#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_CIPHER_C, POLARSSL_MD_C + * and at least one of the POLARSSL_SSL_PROTO_* defines + * + * This module is required for SSL/TLS. + */ +#define POLARSSL_SSL_TLS_C + +/** + * \def POLARSSL_THREADING_C + * + * Enable the threading abstraction layer. + * By default PolarSSL assumes it is used in a non-threaded environment or that + * contexts are not shared between threads. If you do intend to use contexts + * between threads, you will need to enable this layer to prevent race + * conditions. + * + * Module: library/threading.c + * + * This allows different threading implementations (self-implemented or + * provided). + * + * You will have to enable either POLARSSL_THREADING_ALT or + * POLARSSL_THREADING_PTHREAD. + * + * Enable this layer to allow use of mutexes within PolarSSL + */ +//#define POLARSSL_THREADING_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_USE_C + * + * Enable X.509 core for using certificates. + * + * Module: library/x509.c + * Caller: library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c + * + * Requires: POLARSSL_ASN1_PARSE_C, POLARSSL_BIGNUM_C, POLARSSL_OID_C, + * POLARSSL_PK_PARSE_C + * + * This module is required for the X.509 parsing modules. + */ +#define POLARSSL_X509_USE_C + +/** + * \def POLARSSL_X509_CRT_PARSE_C + * + * Enable X.509 certificate parsing. + * + * Module: library/x509_crt.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * Requires: POLARSSL_X509_USE_C + * + * This module is required for X.509 certificate parsing. + */ +#define POLARSSL_X509_CRT_PARSE_C + +/** + * \def POLARSSL_X509_CRL_PARSE_C + * + * Enable X.509 CRL parsing. + * + * Module: library/x509_crl.c + * Caller: library/x509_crt.c + * + * Requires: POLARSSL_X509_USE_C + * + * This module is required for X.509 CRL parsing. + */ +#define POLARSSL_X509_CRL_PARSE_C + +/** + * \def POLARSSL_X509_CSR_PARSE_C + * + * Enable X.509 Certificate Signing Request (CSR) parsing. + * + * Module: library/x509_csr.c + * Caller: library/x509_crt_write.c + * + * Requires: POLARSSL_X509_USE_C + * + * This module is used for reading X.509 certificate request. + */ +// JY removed -- PKI +//#define POLARSSL_X509_CSR_PARSE_C + +/** + * \def POLARSSL_X509_CREATE_C + * + * Enable X.509 core for creating certificates. + * + * Module: library/x509_create.c + * + * Requires: POLARSSL_BIGNUM_C, POLARSSL_OID_C, POLARSSL_PK_WRITE_C + * + * This module is the basis for creating X.509 certificates and CSRs. + */ +// JY removed -- PKI +//#define POLARSSL_X509_CREATE_C + +/** + * \def POLARSSL_X509_CRT_WRITE_C + * + * Enable creating X.509 certificates. + * + * Module: library/x509_crt_write.c + * + * Requires: POLARSSL_CREATE_C + * + * This module is required for X.509 certificate creation. + */ +// JY removed -- PKI +//#define POLARSSL_X509_CRT_WRITE_C + +/** + * \def POLARSSL_X509_CSR_WRITE_C + * + * Enable creating X.509 Certificate Signing Requests (CSR). + * + * Module: library/x509_csr_write.c + * + * Requires: POLARSSL_CREATE_C + * + * This module is required for X.509 certificate request writing. + */ +// JY removed -- PKI +//#define POLARSSL_X509_CSR_WRITE_C + +/** + * \def POLARSSL_XTEA_C + * + * Enable the XTEA block cipher. + * + * Module: library/xtea.c + * Caller: + */ +// JY removed -- crypto +//#define POLARSSL_XTEA_C + +/* \} name SECTION: PolarSSL modules */ + +/** + * \name SECTION: Module configuration options + * + * This section allows for the setting of module specific sizes and + * configuration options. The default values are already present in the + * relevant header files and should suffice for the regular use cases. + * + * Our advice is to enable options and change their values here + * only if you have a good reason and know the consequences. + * + * Please check the respective header file for documentation on these + * parameters (to prevent duplicate documentation). + * \{ + */ + +/* MPI / BIGNUM options */ +//#define POLARSSL_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ +//#define POLARSSL_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */ + +/* CTR_DRBG options */ +//#define CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */ +//#define CTR_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +//#define CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +/* HMAC_DRBG options */ +//#define POLARSSL_HMAC_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +//#define POLARSSL_HMAC_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define POLARSSL_HMAC_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define POLARSSL_HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +/* ECP options */ +//#define POLARSSL_ECP_MAX_BITS 521 /**< Maximum bit size of groups */ +//#define POLARSSL_ECP_WINDOW_SIZE 6 /**< Maximum window size used */ +//#define POLARSSL_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up */ + +/* Entropy options */ +//#define ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ +//#define ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ + +/* Memory buffer allocator options */ +//#define POLARSSL_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */ + +/* Platform options */ +//#define POLARSSL_PLATFORM_STD_MEM_HDR /**< Header to include if POLARSSL_PLATFORM_NO_STD_FUNCTIONS is defined. Don't define if no header is needed. */ +//#define POLARSSL_PLATFORM_STD_MALLOC malloc /**< Default allocator to use, can be undefined */ +//#define POLARSSL_PLATFORM_STD_FREE free /**< Default free to use, can be undefined */ +//#define POLARSSL_PLATFORM_STD_PRINTF printf /**< Default printf to use, can be undefined */ +//#define POLARSSL_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use, can be undefined */ + +/* SSL Cache options */ +//#define SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */ +//#define SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */ + +/* SSL options */ +//#define SSL_MAX_CONTENT_LEN 16384 /**< Size of the input / output buffer */ +//#define SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ +//#define POLARSSL_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ + +/** + * Complete list of ciphersuites to use, in order of preference. + * + * \warning No dependency checking is done on that field! This option can only + * be used to restrict the set of available ciphersuites. It is your + * responsibility to make sure the needed modules are active. + * + * Use this to save a few hundred bytes of ROM (default ordering of all + * available ciphersuites) and a few to a few hundred bytes of RAM. + * + * The value below is only an example, not the default. + */ +//#define SSL_CIPHERSUITES TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + +/* Debug options */ +//#define POLARSSL_DEBUG_DFL_MODE POLARSSL_DEBUG_LOG_FULL /**< Default log: Full or Raw */ + +/* \} name SECTION: Module configuration options */ + +#include "check_config.h" + +#endif /* POLARSSL_CONFIG_H */ diff --git a/deps/polarssl/config.h.orig b/deps/polarssl/config.h.orig new file mode 100644 index 0000000..50b4e33 --- /dev/null +++ b/deps/polarssl/config.h.orig @@ -0,0 +1,2180 @@ +/** + * \file config.h + * + * \brief Configuration options (set of defines) + * + * Copyright (C) 2006-2014, Brainspark B.V. + * + * This file is part of PolarSSL (http://www.polarssl.org) + * Lead Maintainer: Paul Bakker + * + * 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 + +#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(). + * + * Requires support for asm() in compiler. + * + * Used in: + * library/timing.c + * library/padlock.c + * include/polarssl/bn_mul.h + * + * Comment to disable the use of assembly code. + */ +#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 + +/** + * \def POLARSSL_HAVE_TIME + * + * System has time.h and time() / localtime() / gettimeofday(). + * + * Comment if your system does not support time functions + */ +#define POLARSSL_HAVE_TIME + +/** + * \def POLARSSL_HAVE_IPV6 + * + * System supports the basic socket interface for IPv6 (RFC 3493), + * specifically getaddrinfo(), freeaddrinfo() and struct sockaddr_storage. + * + * Note: on Windows/MingW, XP or higher is required. + * + * Comment if your system does not support the IPv6 socket interface + */ +#define POLARSSL_HAVE_IPV6 + +/** + * \def POLARSSL_PLATFORM_MEMORY + * + * Enable the memory allocation layer. + * + * By default PolarSSL uses the system-provided malloc() and free(). + * This allows different allocators (self-implemented or provided) to be + * provided to the platform abstraction layer. + * + * Enabling POLARSSL_PLATFORM_MEMORY will provide "platform_set_malloc_free()" + * to allow you to set an alternative malloc() and free() function pointer. + * + * Requires: POLARSSL_PLATFORM_C + * + * Enable this layer to allow use of alternative memory allocators. + */ +//#define POLARSSL_PLATFORM_MEMORY + +/** + * \def POLARSSL_PLATFORM_NO_STD_FUNCTIONS + * + * Do not assign standard functions in the platform layer (e.g. malloc() to + * POLARSSL_PLATFORM_STD_MALLOC and printf() to POLARSSL_PLATFORM_STD_PRINTF) + * + * This makes sure there are no linking errors on platforms that do not support + * these functions. You will HAVE to provide alternatives, either at runtime + * via the platform_set_xxx() functions or at compile time by setting + * the POLARSSL_PLATFORM_STD_XXX defines. + * + * Requires: POLARSSL_PLATFORM_C + * + * Uncomment to prevent default assignment of standard functions in the + * platform layer. + */ +//#define POLARSSL_PLATFORM_NO_STD_FUNCTIONS + +/** + * \def POLARSSL_PLATFORM_XXX_ALT + * + * Uncomment a macro to let PolarSSL support the function in the platform + * abstraction layer. + * + * Example: In case you uncomment POLARSSL_PLATFORM_PRINTF_ALT, PolarSSL will + * provide a function "platform_set_printf()" that allows you to set an + * alternative printf function pointer. + * + * All these define require POLARSSL_PLATFORM_C to be defined! + * + * Uncomment a macro to enable alternate implementation of specific base + * platform function + */ +//#define POLARSSL_PLATFORM_PRINTF_ALT +//#define POLARSSL_PLATFORM_FPRINTF_ALT +/* \} name SECTION: System support */ + +/** + * \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_TIMING_ALT + * + * Uncomment to provide your own alternate implementation for hardclock(), + * get_timer(), set_alarm() and m_sleep(). + * + * Only works if you have POLARSSL_TIMING_C enabled. + * + * You will need to provide a header "timing_alt.h" and an implementation at + * compile time. + */ +//#define POLARSSL_TIMING_ALT + +/** + * \def POLARSSL_XXX_ALT + * + * Uncomment a macro to let PolarSSL use your alternate core implementation of + * a symmetric or hash algorithm (e.g. platform specific assembly optimized + * implementations). Keep in mind that the function prototypes should remain + * the same. + * + * Example: In case you uncomment POLARSSL_AES_ALT, PolarSSL will no longer + * provide the "struct aes_context" definition and omit the base function + * declarations and implementations. "aes_alt.h" will be included from + * "aes.h" to include the new function definitions. + * + * Uncomment a macro to enable alternate implementation for core algorithm + * functions + */ +//#define POLARSSL_AES_ALT +//#define POLARSSL_ARC4_ALT +//#define POLARSSL_BLOWFISH_ALT +//#define POLARSSL_CAMELLIA_ALT +//#define POLARSSL_DES_ALT +//#define POLARSSL_XTEA_ALT +//#define POLARSSL_MD2_ALT +//#define POLARSSL_MD4_ALT +//#define POLARSSL_MD5_ALT +//#define POLARSSL_RIPEMD160_ALT +//#define POLARSSL_SHA1_ALT +//#define POLARSSL_SHA256_ALT +//#define POLARSSL_SHA512_ALT + +/** + * \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_CBC + * + * Enable Cipher Block Chaining mode (CBC) for symmetric ciphers. + */ +#define POLARSSL_CIPHER_MODE_CBC + +/** + * \def POLARSSL_CIPHER_MODE_CFB + * + * Enable Cipher Feedback mode (CFB) for symmetric ciphers. + */ +#define POLARSSL_CIPHER_MODE_CFB + +/** + * \def POLARSSL_CIPHER_MODE_CTR + * + * Enable Counter Block Cipher mode (CTR) for symmetric ciphers. + */ +#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_ECDH_ECDSA_WITH_NULL_SHA + * TLS_ECDH_RSA_WITH_NULL_SHA + * TLS_ECDHE_ECDSA_WITH_NULL_SHA + * TLS_ECDHE_RSA_WITH_NULL_SHA + * TLS_ECDHE_PSK_WITH_NULL_SHA384 + * TLS_ECDHE_PSK_WITH_NULL_SHA256 + * TLS_ECDHE_PSK_WITH_NULL_SHA + * TLS_DHE_PSK_WITH_NULL_SHA384 + * TLS_DHE_PSK_WITH_NULL_SHA256 + * TLS_DHE_PSK_WITH_NULL_SHA + * TLS_RSA_WITH_NULL_SHA256 + * TLS_RSA_WITH_NULL_SHA + * TLS_RSA_WITH_NULL_MD5 + * TLS_RSA_PSK_WITH_NULL_SHA384 + * TLS_RSA_PSK_WITH_NULL_SHA256 + * TLS_RSA_PSK_WITH_NULL_SHA + * TLS_PSK_WITH_NULL_SHA384 + * TLS_PSK_WITH_NULL_SHA256 + * TLS_PSK_WITH_NULL_SHA + * + * Uncomment this macro to enable the NULL cipher and ciphersuites + */ +//#define POLARSSL_CIPHER_NULL_CIPHER + +/** + * \def POLARSSL_CIPHER_PADDING_XXX + * + * Uncomment or comment macros to add support for specific padding modes + * in the cipher layer with cipher modes that support padding (e.g. CBC) + * + * If you disable all padding modes, only full blocks can be used with CBC. + * + * Enable padding modes in the cipher layer. + */ +#define POLARSSL_CIPHER_PADDING_PKCS7 +#define POLARSSL_CIPHER_PADDING_ONE_AND_ZEROS +#define POLARSSL_CIPHER_PADDING_ZEROS_AND_LEN +#define POLARSSL_CIPHER_PADDING_ZEROS + +/** + * \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_REMOVE_ARC4_CIPHERSUITES + * + * Remove RC4 ciphersuites by default in SSL / TLS. + * This flag removes the ciphersuites based on RC4 from the default list as + * returned by ssl_list_ciphersuites(). However, it is still possible to + * enable (some of) them with ssl_set_ciphersuites() by including them + * explicitly. + * + * Uncomment this macro to remove RC4 ciphersuites by default. + */ +//#define POLARSSL_REMOVE_ARC4_CIPHERSUITES + +/** + * \def POLARSSL_ECP_XXXX_ENABLED + * + * Enables specific curves within the Elliptic Curve module. + * By default all supported curves are enabled. + * + * Comment macros to disable the curve and functions for it + */ +#define POLARSSL_ECP_DP_SECP192R1_ENABLED +#define POLARSSL_ECP_DP_SECP224R1_ENABLED +#define POLARSSL_ECP_DP_SECP256R1_ENABLED +#define POLARSSL_ECP_DP_SECP384R1_ENABLED +#define POLARSSL_ECP_DP_SECP521R1_ENABLED +#define POLARSSL_ECP_DP_SECP192K1_ENABLED +#define POLARSSL_ECP_DP_SECP224K1_ENABLED +#define POLARSSL_ECP_DP_SECP256K1_ENABLED +#define POLARSSL_ECP_DP_BP256R1_ENABLED +#define POLARSSL_ECP_DP_BP384R1_ENABLED +#define POLARSSL_ECP_DP_BP512R1_ENABLED +//#define POLARSSL_ECP_DP_M221_ENABLED // Not implemented yet! +#define POLARSSL_ECP_DP_M255_ENABLED +//#define POLARSSL_ECP_DP_M383_ENABLED // Not implemented yet! +//#define POLARSSL_ECP_DP_M511_ENABLED // Not implemented yet! + +/** + * \def POLARSSL_ECP_NIST_OPTIM + * + * Enable specific 'modulo p' routines for each NIST prime. + * Depending on the prime and architecture, makes operations 4 to 8 times + * faster on the corresponding curve. + * + * Comment this macro to disable NIST curves optimisation. + */ +#define POLARSSL_ECP_NIST_OPTIM + +/** + * \def POLARSSL_ECDSA_DETERMINISTIC + * + * Enable deterministic ECDSA (RFC 6979). + * Standard ECDSA is "fragile" in the sense that lack of entropy when signing + * may result in a compromise of the long-term signing key. This is avoided by + * the deterministic variant. + * + * Requires: POLARSSL_HMAC_DRBG_C + * + * Comment this macro to disable deterministic ECDSA. + */ +#define POLARSSL_ECDSA_DETERMINISTIC + +/** + * \def POLARSSL_KEY_EXCHANGE_PSK_ENABLED + * + * Enable the PSK based ciphersuite modes in SSL / TLS. + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_PSK_WITH_AES_256_GCM_SHA384 + * TLS_PSK_WITH_AES_256_CBC_SHA384 + * TLS_PSK_WITH_AES_256_CBC_SHA + * TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_PSK_WITH_AES_128_GCM_SHA256 + * TLS_PSK_WITH_AES_128_CBC_SHA256 + * TLS_PSK_WITH_AES_128_CBC_SHA + * TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_PSK_WITH_3DES_EDE_CBC_SHA + * TLS_PSK_WITH_RC4_128_SHA + */ +#define POLARSSL_KEY_EXCHANGE_PSK_ENABLED + +/** + * \def POLARSSL_KEY_EXCHANGE_DHE_PSK_ENABLED + * + * Enable the DHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: POLARSSL_DHM_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * TLS_DHE_PSK_WITH_AES_128_CBC_SHA + * TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA + * TLS_DHE_PSK_WITH_RC4_128_SHA + */ +#define POLARSSL_KEY_EXCHANGE_DHE_PSK_ENABLED + +/** + * \def POLARSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED + * + * Enable the ECDHE-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: POLARSSL_ECDH_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + * TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + * TLS_ECDHE_PSK_WITH_RC4_128_SHA + */ +#define POLARSSL_KEY_EXCHANGE_ECDHE_PSK_ENABLED + +/** + * \def POLARSSL_KEY_EXCHANGE_RSA_PSK_ENABLED + * + * Enable the RSA-PSK based ciphersuite modes in SSL / TLS. + * + * Requires: POLARSSL_RSA_C, POLARSSL_PKCS1_V15, + * POLARSSL_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * TLS_RSA_PSK_WITH_AES_128_CBC_SHA + * TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA + * TLS_RSA_PSK_WITH_RC4_128_SHA + */ +#define POLARSSL_KEY_EXCHANGE_RSA_PSK_ENABLED + +/** + * \def POLARSSL_KEY_EXCHANGE_RSA_ENABLED + * + * Enable the RSA-only based ciphersuite modes in SSL / TLS. + * + * Requires: POLARSSL_RSA_C, POLARSSL_PKCS1_V15, + * POLARSSL_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_RSA_WITH_AES_256_GCM_SHA384 + * TLS_RSA_WITH_AES_256_CBC_SHA256 + * TLS_RSA_WITH_AES_256_CBC_SHA + * TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + * TLS_RSA_WITH_AES_128_GCM_SHA256 + * TLS_RSA_WITH_AES_128_CBC_SHA256 + * TLS_RSA_WITH_AES_128_CBC_SHA + * TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + * TLS_RSA_WITH_3DES_EDE_CBC_SHA + * TLS_RSA_WITH_RC4_128_SHA + * TLS_RSA_WITH_RC4_128_MD5 + */ +#define POLARSSL_KEY_EXCHANGE_RSA_ENABLED + +/** + * \def POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED + * + * Enable the DHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: POLARSSL_DHM_C, POLARSSL_RSA_C, POLARSSL_PKCS1_V15, + * POLARSSL_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + */ +#define POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED + +/** + * \def POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED + * + * Enable the ECDHE-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: POLARSSL_ECDH_C, POLARSSL_RSA_C, POLARSSL_PKCS1_V15, + * POLARSSL_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + * TLS_ECDHE_RSA_WITH_RC4_128_SHA + */ +#define POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED + +/** + * \def POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + * + * Enable the ECDHE-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: POLARSSL_ECDH_C, POLARSSL_ECDSA_C, POLARSSL_X509_CRT_PARSE_C, + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + * TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + */ +#define POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED + +/** + * \def POLARSSL_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + * + * Enable the ECDH-ECDSA based ciphersuite modes in SSL / TLS. + * + * Requires: POLARSSL_ECDH_C, POLARSSL_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + * TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + */ +#define POLARSSL_KEY_EXCHANGE_ECDH_ECDSA_ENABLED + +/** + * \def POLARSSL_KEY_EXCHANGE_ECDH_RSA_ENABLED + * + * Enable the ECDH-RSA based ciphersuite modes in SSL / TLS. + * + * Requires: POLARSSL_ECDH_C, POLARSSL_X509_CRT_PARSE_C + * + * This enables the following ciphersuites (if other requisites are + * enabled as well): + * TLS_ECDH_RSA_WITH_RC4_128_SHA + * TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + * TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + */ +#define POLARSSL_KEY_EXCHANGE_ECDH_RSA_ENABLED + +/** + * \def POLARSSL_PK_PARSE_EC_EXTENDED + * + * Enhance support for reading EC keys using variants of SEC1 not allowed by + * RFC 5915 and RFC 5480. + * + * Currently this means parsing the SpecifiedECDomain choice of EC + * parameters (only known groups are supported, not arbitrary domains, to + * avoid validation issues). + * + * Disable if you only need to support RFC 5915 + 5480 key formats. + */ +#define POLARSSL_PK_PARSE_EC_EXTENDED + +/** + * \def POLARSSL_ERROR_STRERROR_BC + * + * Make available the backward compatible error_strerror() next to the + * current polarssl_strerror(). + * + * For new code, it is recommended to use polarssl_strerror() instead and + * disable this. + * + * Disable if you run into name conflicts and want to really remove the + * error_strerror() + */ +#define POLARSSL_ERROR_STRERROR_BC + +/** + * \def POLARSSL_ERROR_STRERROR_DUMMY + * + * Enable a dummy error function to make use of polarssl_strerror() in + * third party libraries easier when POLARSSL_ERROR_C is disabled + * (no effect when POLARSSL_ERROR_C is enabled). + * + * You can safely disable this if POLARSSL_ERROR_C is enabled, or if you're + * not using polarssl_strerror() or error_strerror() in your application. + * + * Disable if you run into name conflicts and want to really remove the + * polarssl_strerror() + */ +#define POLARSSL_ERROR_STRERROR_DUMMY + +/** + * \def POLARSSL_GENPRIME + * + * Enable the prime-number generation code. + * + * Requires: POLARSSL_BIGNUM_C + */ +#define POLARSSL_GENPRIME + +/** + * \def POLARSSL_FS_IO + * + * Enable functions that use the filesystem. + */ +#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 + +/** + * \def POLARSSL_ENTROPY_FORCE_SHA256 + * + * Force the entropy accumulator to use a SHA-256 accumulator instead of the + * default SHA-512 based one (if both are available). + * + * Requires: POLARSSL_SHA256_C + * + * On 32-bit systems SHA-256 can be much faster than SHA-512. Use this option + * if you have performance concerns. + * + * This option is only useful if both POLARSSL_SHA256_C and + * POLARSSL_SHA512_C are defined. Otherwise the available hash module is used. + */ +//#define POLARSSL_ENTROPY_FORCE_SHA256 + +/** + * \def POLARSSL_MEMORY_DEBUG + * + * Enable debugging of buffer allocator memory issues. Automatically prints + * (to stderr) all (fatal) messages on memory allocation issues. Enables + * function for 'debug output' of allocated memory. + * + * Requires: POLARSSL_MEMORY_BUFFER_ALLOC_C + * + * Uncomment this macro to let the buffer allocator print out error messages. + */ +//#define POLARSSL_MEMORY_DEBUG + +/** + * \def POLARSSL_MEMORY_BACKTRACE + * + * Include backtrace information with each allocated block. + * + * Requires: POLARSSL_MEMORY_BUFFER_ALLOC_C + * GLIBC-compatible backtrace() an backtrace_symbols() support + * + * Uncomment this macro to include backtrace information + */ +//#define POLARSSL_MEMORY_BACKTRACE + +/** + * \def POLARSSL_PKCS1_V15 + * + * Enable support for PKCS#1 v1.5 encoding. + * + * Requires: POLARSSL_RSA_C + * + * This enables support for PKCS#1 v1.5 operations. + */ +#define POLARSSL_PKCS1_V15 + +/** + * \def POLARSSL_PKCS1_V21 + * + * Enable support for PKCS#1 v2.1 encoding. + * + * Requires: POLARSSL_MD_C, POLARSSL_RSA_C + * + * 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). + */ +#define POLARSSL_SELF_TEST + +/** + * \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. + */ +#define POLARSSL_SSL_SRV_SUPPORT_SSLV2_CLIENT_HELLO + +/** + * \def POLARSSL_SSL_SRV_RESPECT_CLIENT_PREFERENCE + * + * Pick the ciphersuite according to the client's preferences rather than ours + * in the SSL Server module (POLARSSL_SSL_SRV_C). + * + * Uncomment this macro to respect client's ciphersuite order + */ +//#define POLARSSL_SSL_SRV_RESPECT_CLIENT_PREFERENCE + +/** + * \def POLARSSL_SSL_MAX_FRAGMENT_LENGTH + * + * Enable support for RFC 6066 max_fragment_length extension in SSL. + * + * Comment this macro to disable support for the max_fragment_length extension + */ +#define POLARSSL_SSL_MAX_FRAGMENT_LENGTH + +/** + * \def POLARSSL_SSL_PROTO_SSL3 + * + * Enable support for SSL 3.0. + * + * Requires: POLARSSL_MD5_C + * POLARSSL_SHA1_C + * + * Comment this macro to disable support for SSL 3.0 + */ +#define POLARSSL_SSL_PROTO_SSL3 + +/** + * \def POLARSSL_SSL_PROTO_TLS1 + * + * Enable support for TLS 1.0. + * + * Requires: POLARSSL_MD5_C + * POLARSSL_SHA1_C + * + * Comment this macro to disable support for TLS 1.0 + */ +#define POLARSSL_SSL_PROTO_TLS1 + +/** + * \def POLARSSL_SSL_PROTO_TLS1_1 + * + * Enable support for TLS 1.1. + * + * Requires: POLARSSL_MD5_C + * POLARSSL_SHA1_C + * + * Comment this macro to disable support for TLS 1.1 + */ +#define POLARSSL_SSL_PROTO_TLS1_1 + +/** + * \def POLARSSL_SSL_PROTO_TLS1_2 + * + * Enable support for TLS 1.2. + * + * Requires: POLARSSL_SHA1_C or POLARSSL_SHA256_C or POLARSSL_SHA512_C + * (Depends on ciphersuites) + * + * Comment this macro to disable support for TLS 1.2 + */ +#define POLARSSL_SSL_PROTO_TLS1_2 + +/** + * \def POLARSSL_SSL_ALPN + * + * Enable support for Application Layer Protocol Negotiation. + * draft-ietf-tls-applayerprotoneg-05 + * + * Comment this macro to disable support for ALPN. + */ +#define POLARSSL_SSL_ALPN + +/** + * \def POLARSSL_SSL_SESSION_TICKETS + * + * Enable support for RFC 5077 session tickets in SSL. + * + * Requires: POLARSSL_AES_C + * POLARSSL_SHA256_C + * POLARSSL_CIPHER_MODE_CBC + * + * Comment this macro to disable support for SSL session tickets + */ +#define POLARSSL_SSL_SESSION_TICKETS + +/** + * \def POLARSSL_SSL_SERVER_NAME_INDICATION + * + * Enable support for RFC 6066 server name indication (SNI) in SSL. + * + * Comment this macro to disable support for server name indication in SSL + */ +#define POLARSSL_SSL_SERVER_NAME_INDICATION + +/** + * \def POLARSSL_SSL_TRUNCATED_HMAC + * + * Enable support for RFC 6066 truncated HMAC in SSL. + * + * Comment this macro to disable support for truncated HMAC in SSL + */ +#define POLARSSL_SSL_TRUNCATED_HMAC + +/** + * \def POLARSSL_SSL_SET_CURVES + * + * Enable ssl_set_curves(). + * + * This is disabled by default since it breaks binary compatibility with the + * 1.3.x line. If you choose to enable it, you will need to rebuild your + * application against the new header files, relinking will not be enough. + * It will be enabled by default, or no longer an option, in the 1.4 branch. + * + * Uncomment to make ssl_set_curves() available. + */ +//#define POLARSSL_SSL_SET_CURVES + +/** + * \def POLARSSL_THREADING_ALT + * + * Provide your own alternate threading implementation. + * + * Requires: POLARSSL_THREADING_C + * + * Uncomment this to allow your own alternate threading implementation. + */ +//#define POLARSSL_THREADING_ALT + +/** + * \def POLARSSL_THREADING_PTHREAD + * + * Enable the pthread wrapper layer for the threading layer. + * + * Requires: POLARSSL_THREADING_C + * + * Uncomment this to enable pthread mutexes. + */ +//#define POLARSSL_THREADING_PTHREAD + +/** + * \def POLARSSL_VERSION_FEATURES + * + * Allow run-time checking of compile-time enabled features. Thus allowing users + * to check at run-time if the library is for instance compiled with threading + * support via version_check_feature(). + * + * Requires: POLARSSL_VERSION_C + * + * Comment this to disable run-time checking and save ROM space + */ +#define POLARSSL_VERSION_FEATURES + +/** + * \def POLARSSL_X509_ALLOW_EXTENSIONS_NON_V3 + * + * If set, the X509 parser will not break-off when parsing an X509 certificate + * and encountering an extension in a v1 or v2 certificate. + * + * Uncomment to prevent an error. + */ +//#define POLARSSL_X509_ALLOW_EXTENSIONS_NON_V3 + +/** + * \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_X509_CHECK_KEY_USAGE + * + * Enable verification of the keyUsage extension (CA and leaf certificates). + * + * Disabling this avoids problems with mis-issued and/or misused + * (intermediate) CA and leaf certificates. + * + * \warning Depending on your PKI use, disabling this can be a security risk! + * + * Comment to skip keyUsage checking for both CA and leaf certificates. + */ +#define POLARSSL_X509_CHECK_KEY_USAGE + +/** + * \def POLARSSL_X509_CHECK_EXTENDED_KEY_USAGE + * + * Enable verification of the extendedKeyUsage extension (leaf certificates). + * + * Disabling this avoids problems with mis-issued and/or misused certificates. + * + * \warning Depending on your PKI use, disabling this can be a security risk! + * + * Comment to skip extendedKeyUsage checking for certificates. + */ +#define POLARSSL_X509_CHECK_EXTENDED_KEY_USAGE + +/** + * \def POLARSSL_X509_RSASSA_PSS_SUPPORT + * + * Enable parsing and verification of X.509 certificates, CRLs and CSRS + * signed with RSASSA-PSS (aka PKCS#1 v2.1). + * + * Comment this macro to disallow using RSASSA-PSS in certificates. + */ +#define POLARSSL_X509_RSASSA_PSS_SUPPORT + +/** + * \def POLARSSL_ZLIB_SUPPORT + * + * If set, the SSL/TLS module uses ZLIB to support compression and + * decompression of packet data. + * + * \warning TLS-level compression MAY REDUCE SECURITY! See for example the + * CRIME attack. Before enabling this option, you should examine with care if + * CRIME or similar exploits may be a applicable to your use case. + * + * 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 SECTION: PolarSSL feature support */ + +/** + * \name SECTION: PolarSSL modules + * + * This section enables or disables entire modules in PolarSSL + * \{ + */ + +/** + * \def POLARSSL_AESNI_C + * + * Enable AES-NI support on x86-64. + * + * Module: library/aesni.c + * Caller: library/aes.c + * + * Requires: POLARSSL_HAVE_ASM + * + * This modules adds support for the AES-NI instructions on x86-64 + */ +#define POLARSSL_AESNI_C + +/** + * \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_ECDH_ECDSA_WITH_AES_128_CBC_SHA + * TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + * TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + * TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + * TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + * TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + * TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + * TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + * TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + * TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + * TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + * TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + * TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + * TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + * TLS_DHE_RSA_WITH_AES_256_CBC_SHA + * TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + * TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + * TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + * TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + * TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + * TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + * TLS_DHE_RSA_WITH_AES_128_CBC_SHA + * TLS_DHE_PSK_WITH_AES_256_GCM_SHA384 + * TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384 + * TLS_DHE_PSK_WITH_AES_256_CBC_SHA384 + * TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA + * TLS_DHE_PSK_WITH_AES_256_CBC_SHA + * TLS_DHE_PSK_WITH_AES_128_GCM_SHA256 + * TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256 + * TLS_DHE_PSK_WITH_AES_128_CBC_SHA256 + * TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA + * TLS_DHE_PSK_WITH_AES_128_CBC_SHA + * TLS_RSA_WITH_AES_256_GCM_SHA384 + * TLS_RSA_WITH_AES_256_CBC_SHA256 + * TLS_RSA_WITH_AES_256_CBC_SHA + * TLS_RSA_WITH_AES_128_GCM_SHA256 + * TLS_RSA_WITH_AES_128_CBC_SHA256 + * TLS_RSA_WITH_AES_128_CBC_SHA + * TLS_RSA_PSK_WITH_AES_256_GCM_SHA384 + * TLS_RSA_PSK_WITH_AES_256_CBC_SHA384 + * TLS_RSA_PSK_WITH_AES_256_CBC_SHA + * TLS_RSA_PSK_WITH_AES_128_GCM_SHA256 + * TLS_RSA_PSK_WITH_AES_128_CBC_SHA256 + * TLS_RSA_PSK_WITH_AES_128_CBC_SHA + * TLS_PSK_WITH_AES_256_GCM_SHA384 + * TLS_PSK_WITH_AES_256_CBC_SHA384 + * TLS_PSK_WITH_AES_256_CBC_SHA + * TLS_PSK_WITH_AES_128_GCM_SHA256 + * TLS_PSK_WITH_AES_128_CBC_SHA256 + * TLS_PSK_WITH_AES_128_CBC_SHA + * + * PEM_PARSE 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 (if other requisites are + * enabled as well): + * TLS_ECDH_ECDSA_WITH_RC4_128_SHA + * TLS_ECDH_RSA_WITH_RC4_128_SHA + * TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + * TLS_ECDHE_RSA_WITH_RC4_128_SHA + * TLS_ECDHE_PSK_WITH_RC4_128_SHA + * TLS_DHE_PSK_WITH_RC4_128_SHA + * TLS_RSA_WITH_RC4_128_SHA + * TLS_RSA_WITH_RC4_128_MD5 + * TLS_RSA_PSK_WITH_RC4_128_SHA + * TLS_PSK_WITH_RC4_128_SHA + */ +#define POLARSSL_ARC4_C + +/** + * \def POLARSSL_ASN1_PARSE_C + * + * Enable the generic ASN1 parser. + * + * Module: library/asn1.c + * Caller: library/x509.c + * library/dhm.c + * library/pkcs12.c + * library/pkcs5.c + * library/pkparse.c + */ +#define POLARSSL_ASN1_PARSE_C + +/** + * \def POLARSSL_ASN1_WRITE_C + * + * Enable the generic ASN1 writer. + * + * Module: library/asn1write.c + * Caller: library/ecdsa.c + * library/pkwrite.c + * library/x509_create.c + * library/x509write_crt.c + * library/x509write_csr.c + */ +#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/ecp.c + * library/ecdsa.c + * library/rsa.c + * library/ssl_tls.c + * + * This module is required for RSA, DHM and ECC (ECDH, ECDSA) 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_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + * TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + * TLS_DHE_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_DHE_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + * TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + * TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + * TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256 + * TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384 + * TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384 + * TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256 + * TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256 + */ +#define POLARSSL_CAMELLIA_C + +/** + * \def POLARSSL_CCM_C + * + * Enable the Counter with CBC-MAC (CCM) mode for 128-bit block cipher. + * + * Module: library/ccm.c + * + * Requires: POLARSSL_AES_C or POLARSSL_CAMELLIA_C + * + * This module enables the AES-CCM ciphersuites, if other requisites are + * enabled as well. + */ +#define POLARSSL_CCM_C + +/** + * \def POLARSSL_CERTS_C + * + * Enable the test certificates. + * + * Module: library/certs.c + * Caller: + * + * Requires: POLARSSL_PEM_PARSE_C + * + * This module is used for testing (ssl_client/server). + */ +#define POLARSSL_CERTS_C + +/** + * \def POLARSSL_CIPHER_C + * + * Enable the generic cipher layer. + * + * Module: library/cipher.c + * Caller: library/ssl_tls.c + * + * 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. + */ +#define POLARSSL_CTR_DRBG_C + +/** + * \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_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + * TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + * TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + * TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + * TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + * TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA + * TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA + * TLS_RSA_WITH_3DES_EDE_CBC_SHA + * TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA + * TLS_PSK_WITH_3DES_EDE_CBC_SHA + * + * PEM_PARSE uses DES/3DES for decrypting encrypted keys. + */ +#define POLARSSL_DES_C + +/** + * \def POLARSSL_DHM_C + * + * Enable the Diffie-Hellman-Merkle module. + * + * Module: library/dhm.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * DHE-RSA, DHE-PSK + */ +#define POLARSSL_DHM_C + +/** + * \def POLARSSL_ECDH_C + * + * Enable the elliptic curve Diffie-Hellman library. + * + * Module: library/ecdh.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA, ECDHE-RSA, DHE-PSK + * + * Requires: POLARSSL_ECP_C + */ +#define POLARSSL_ECDH_C + +/** + * \def POLARSSL_ECDSA_C + * + * Enable the elliptic curve DSA library. + * + * Module: library/ecdsa.c + * Caller: + * + * This module is used by the following key exchanges: + * ECDHE-ECDSA + * + * Requires: POLARSSL_ECP_C, POLARSSL_ASN1_WRITE_C, POLARSSL_ASN1_PARSE_C + */ +#define POLARSSL_ECDSA_C + +/** + * \def POLARSSL_ECP_C + * + * Enable the elliptic curve over GF(p) library. + * + * Module: library/ecp.c + * Caller: library/ecdh.c + * library/ecdsa.c + * + * Requires: POLARSSL_BIGNUM_C and at least one POLARSSL_ECP_DP_XXX_ENABLED + */ +#define POLARSSL_ECP_C + +/** + * \def POLARSSL_ENTROPY_C + * + * Enable the platform-specific entropy code. + * + * Module: library/entropy.c + * Caller: + * + * Requires: POLARSSL_SHA512_C or POLARSSL_SHA256_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 polarssl_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 or POLARSSL_CAMELLIA_C + * + * This module enables the AES-GCM and CAMELLIA-GCM ciphersuites, if other + * requisites are enabled as well. + */ +#define POLARSSL_GCM_C + +/** + * \def POLARSSL_HAVEGE_C + * + * Enable the HAVEGE random generator. + * + * Warning: the HAVEGE random generator is not suitable for virtualized + * environments + * + * Warning: the HAVEGE random generator is dependent on timing and specific + * processor traits. It is therefore not advised to use HAVEGE as + * your applications primary random generator or primary entropy pool + * input. As a secondary input to your entropy pool, it IS able add + * the (limited) extra entropy it provides. + * + * Module: library/havege.c + * Caller: + * + * Requires: POLARSSL_TIMING_C + * + * Uncomment to enable the HAVEGE random generator. + */ +//#define POLARSSL_HAVEGE_C + +/** + * \def POLARSSL_HMAC_DRBG_C + * + * Enable the HMAC_DRBG random generator. + * + * Module: library/hmac_drbg.c + * Caller: + * + * Requires: POLARSSL_MD_C + * + * Uncomment to enable the HMAC_DRBG random number geerator. + */ +#define POLARSSL_HMAC_DRBG_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: + * + * 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: + * + * Uncomment to enable support for (rare) MD4-signed X.509 certs. + */ +//#define POLARSSL_MD4_C + +/** + * \def POLARSSL_MD5_C + * + * Enable the MD5 hash algorithm. + * + * Module: library/md5.c + * Caller: library/md.c + * library/pem.c + * library/ssl_tls.c + * + * This module is required for SSL/TLS and X.509. + * PEM_PARSE uses MD5 for decrypting encrypted keys. + */ +#define POLARSSL_MD5_C + +/** + * \def POLARSSL_MEMORY_C + * Deprecated since 1.3.5. Please use POLARSSL_PLATFORM_MEMORY instead. + */ +//#define POLARSSL_MEMORY_C + +/** + * \def POLARSSL_MEMORY_BUFFER_ALLOC_C + * + * Enable the buffer allocator implementation that makes use of a (stack) + * based buffer to 'allocate' dynamic memory. (replaces malloc() and free() + * calls) + * + * Module: library/memory_buffer_alloc.c + * + * Requires: POLARSSL_PLATFORM_C + * POLARSSL_PLATFORM_MEMORY (to use it within PolarSSL) + * + * Enable this module to enable the buffer memory allocator. + */ +//#define POLARSSL_MEMORY_BUFFER_ALLOC_C + +/** + * \def POLARSSL_NET_C + * + * Enable the TCP/IP networking routines. + * + * Module: library/net.c + * + * This module provides TCP/IP networking routines. + */ +#define POLARSSL_NET_C + +/** + * \def POLARSSL_OID_C + * + * Enable the OID database. + * + * Module: library/oid.c + * Caller: library/asn1write.c + * library/pkcs5.c + * library/pkparse.c + * library/pkwrite.c + * library/rsa.c + * library/x509.c + * library/x509_create.c + * library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c + * library/x509write_crt.c + * library/x509write_csr.c + * + * This modules translates between OIDs and internal values. + */ +#define POLARSSL_OID_C + +/** + * \def POLARSSL_PADLOCK_C + * + * Enable VIA Padlock support on x86. + * + * Module: library/padlock.c + * Caller: library/aes.c + * + * Requires: POLARSSL_HAVE_ASM + * + * This modules adds support for the VIA PadLock on x86. + */ +#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_PARSE_C + * + * Enable PEM decoding / parsing. + * + * Module: library/pem.c + * Caller: library/dhm.c + * library/pkparse.c + * library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c + * + * Requires: POLARSSL_BASE64_C + * + * This modules adds support for decoding / parsing PEM files. + */ +#define POLARSSL_PEM_PARSE_C + +/** + * \def POLARSSL_PEM_WRITE_C + * + * Enable PEM encoding / writing. + * + * Module: library/pem.c + * Caller: library/pkwrite.c + * library/x509write_crt.c + * library/x509write_csr.c + * + * Requires: POLARSSL_BASE64_C + * + * This modules adds support for encoding / writing PEM files. + */ +#define POLARSSL_PEM_WRITE_C + +/** + * \def POLARSSL_PK_C + * + * Enable the generic public (asymetric) key layer. + * + * Module: library/pk.c + * Caller: library/ssl_tls.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * Requires: POLARSSL_RSA_C or POLARSSL_ECP_C + * + * Uncomment to enable generic public key wrappers. + */ +#define POLARSSL_PK_C + +/** + * \def POLARSSL_PK_PARSE_C + * + * Enable the generic public (asymetric) key parser. + * + * Module: library/pkparse.c + * Caller: library/x509_crt.c + * library/x509_csr.c + * + * Requires: POLARSSL_PK_C + * + * Uncomment to enable generic public key parse functions. + */ +#define POLARSSL_PK_PARSE_C + +/** + * \def POLARSSL_PK_WRITE_C + * + * Enable the generic public (asymetric) key writer. + * + * Module: library/pkwrite.c + * Caller: library/x509write.c + * + * Requires: POLARSSL_PK_C + * + * Uncomment to enable generic public key write functions. + */ +#define POLARSSL_PK_WRITE_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/pkcs11.c + * Caller: library/pk.c + * + * Requires: POLARSSL_PK_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/pkparse.c + * + * Requires: POLARSSL_ASN1_PARSE_C, POLARSSL_CIPHER_C, POLARSSL_MD_C + * Can use: POLARSSL_ARC4_C + * + * This module enables PKCS#12 functions. + */ +#define POLARSSL_PKCS12_C + +/** + * \def POLARSSL_PLATFORM_C + * + * Enable the platform abstraction layer that allows you to re-assign + * functions like malloc(), free(), printf(), fprintf() + * + * Module: library/platform.c + * Caller: Most other .c files + * + * This module enables abstraction of common (libc) functions. + */ +#define POLARSSL_PLATFORM_C + +/** + * \def POLARSSL_RIPEMD160_C + * + * Enable the RIPEMD-160 hash algorithm. + * + * Module: library/ripemd160.c + * Caller: library/md.c + * + */ +#define POLARSSL_RIPEMD160_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 + * + * This module is used by the following key exchanges: + * RSA, DHE-RSA, ECDHE-RSA, RSA-PSK + * + * Requires: POLARSSL_BIGNUM_C, POLARSSL_OID_C + */ +#define POLARSSL_RSA_C + +/** + * \def POLARSSL_SHA1_C + * + * Enable the SHA1 cryptographic hash algorithm. + * + * Module: library/sha1.c + * Caller: library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * library/x509write_crt.c + * + * This module is required for SSL/TLS and SHA1-signed certificates. + */ +#define POLARSSL_SHA1_C + +/** + * \def POLARSSL_SHA256_C + * + * Enable the SHA-224 and SHA-256 cryptographic hash algorithms. + * (Used to be POLARSSL_SHA2_C) + * + * Module: library/sha256.c + * Caller: library/entropy.c + * library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.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_SHA256_C + +/** + * \def POLARSSL_SHA512_C + * + * Enable the SHA-384 and SHA-512 cryptographic hash algorithms. + * (Used to be POLARSSL_SHA4_C) + * + * Module: library/sha512.c + * Caller: library/entropy.c + * library/md.c + * library/ssl_cli.c + * library/ssl_srv.c + * + * This module adds support for SHA-384 and SHA-512. + */ +#define POLARSSL_SHA512_C + +/** + * \def POLARSSL_SSL_CACHE_C + * + * Enable simple SSL cache implementation. + * + * Module: library/ssl_cache.c + * Caller: + * + * Requires: POLARSSL_SSL_CACHE_C + */ +#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. + */ +#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_CIPHER_C, POLARSSL_MD_C + * and at least one of the POLARSSL_SSL_PROTO_* defines + * + * This module is required for SSL/TLS. + */ +#define POLARSSL_SSL_TLS_C + +/** + * \def POLARSSL_THREADING_C + * + * Enable the threading abstraction layer. + * By default PolarSSL assumes it is used in a non-threaded environment or that + * contexts are not shared between threads. If you do intend to use contexts + * between threads, you will need to enable this layer to prevent race + * conditions. + * + * Module: library/threading.c + * + * This allows different threading implementations (self-implemented or + * provided). + * + * You will have to enable either POLARSSL_THREADING_ALT or + * POLARSSL_THREADING_PTHREAD. + * + * Enable this layer to allow use of mutexes within PolarSSL + */ +//#define POLARSSL_THREADING_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. + */ +#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_USE_C + * + * Enable X.509 core for using certificates. + * + * Module: library/x509.c + * Caller: library/x509_crl.c + * library/x509_crt.c + * library/x509_csr.c + * + * Requires: POLARSSL_ASN1_PARSE_C, POLARSSL_BIGNUM_C, POLARSSL_OID_C, + * POLARSSL_PK_PARSE_C + * + * This module is required for the X.509 parsing modules. + */ +#define POLARSSL_X509_USE_C + +/** + * \def POLARSSL_X509_CRT_PARSE_C + * + * Enable X.509 certificate parsing. + * + * Module: library/x509_crt.c + * Caller: library/ssl_cli.c + * library/ssl_srv.c + * library/ssl_tls.c + * + * Requires: POLARSSL_X509_USE_C + * + * This module is required for X.509 certificate parsing. + */ +#define POLARSSL_X509_CRT_PARSE_C + +/** + * \def POLARSSL_X509_CRL_PARSE_C + * + * Enable X.509 CRL parsing. + * + * Module: library/x509_crl.c + * Caller: library/x509_crt.c + * + * Requires: POLARSSL_X509_USE_C + * + * This module is required for X.509 CRL parsing. + */ +#define POLARSSL_X509_CRL_PARSE_C + +/** + * \def POLARSSL_X509_CSR_PARSE_C + * + * Enable X.509 Certificate Signing Request (CSR) parsing. + * + * Module: library/x509_csr.c + * Caller: library/x509_crt_write.c + * + * Requires: POLARSSL_X509_USE_C + * + * This module is used for reading X.509 certificate request. + */ +#define POLARSSL_X509_CSR_PARSE_C + +/** + * \def POLARSSL_X509_CREATE_C + * + * Enable X.509 core for creating certificates. + * + * Module: library/x509_create.c + * + * Requires: POLARSSL_BIGNUM_C, POLARSSL_OID_C, POLARSSL_PK_WRITE_C + * + * This module is the basis for creating X.509 certificates and CSRs. + */ +#define POLARSSL_X509_CREATE_C + +/** + * \def POLARSSL_X509_CRT_WRITE_C + * + * Enable creating X.509 certificates. + * + * Module: library/x509_crt_write.c + * + * Requires: POLARSSL_CREATE_C + * + * This module is required for X.509 certificate creation. + */ +#define POLARSSL_X509_CRT_WRITE_C + +/** + * \def POLARSSL_X509_CSR_WRITE_C + * + * Enable creating X.509 Certificate Signing Requests (CSR). + * + * Module: library/x509_csr_write.c + * + * Requires: POLARSSL_CREATE_C + * + * This module is required for X.509 certificate request writing. + */ +#define POLARSSL_X509_CSR_WRITE_C + +/** + * \def POLARSSL_XTEA_C + * + * Enable the XTEA block cipher. + * + * Module: library/xtea.c + * Caller: + */ +#define POLARSSL_XTEA_C + +/* \} name SECTION: PolarSSL modules */ + +/** + * \name SECTION: Module configuration options + * + * This section allows for the setting of module specific sizes and + * configuration options. The default values are already present in the + * relevant header files and should suffice for the regular use cases. + * + * Our advice is to enable options and change their values here + * only if you have a good reason and know the consequences. + * + * Please check the respective header file for documentation on these + * parameters (to prevent duplicate documentation). + * \{ + */ + +/* MPI / BIGNUM options */ +//#define POLARSSL_MPI_WINDOW_SIZE 6 /**< Maximum windows size used. */ +//#define POLARSSL_MPI_MAX_SIZE 1024 /**< Maximum number of bytes for usable MPIs. */ + +/* CTR_DRBG options */ +//#define CTR_DRBG_ENTROPY_LEN 48 /**< Amount of entropy used per seed by default (48 with SHA-512, 32 with SHA-256) */ +//#define CTR_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +//#define CTR_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define CTR_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define CTR_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +/* HMAC_DRBG options */ +//#define POLARSSL_HMAC_DRBG_RESEED_INTERVAL 10000 /**< Interval before reseed is performed by default */ +//#define POLARSSL_HMAC_DRBG_MAX_INPUT 256 /**< Maximum number of additional input bytes */ +//#define POLARSSL_HMAC_DRBG_MAX_REQUEST 1024 /**< Maximum number of requested bytes per call */ +//#define POLARSSL_HMAC_DRBG_MAX_SEED_INPUT 384 /**< Maximum size of (re)seed buffer */ + +/* ECP options */ +//#define POLARSSL_ECP_MAX_BITS 521 /**< Maximum bit size of groups */ +//#define POLARSSL_ECP_WINDOW_SIZE 6 /**< Maximum window size used */ +//#define POLARSSL_ECP_FIXED_POINT_OPTIM 1 /**< Enable fixed-point speed-up */ + +/* Entropy options */ +//#define ENTROPY_MAX_SOURCES 20 /**< Maximum number of sources supported */ +//#define ENTROPY_MAX_GATHER 128 /**< Maximum amount requested from entropy sources */ + +/* Memory buffer allocator options */ +//#define POLARSSL_MEMORY_ALIGN_MULTIPLE 4 /**< Align on multiples of this value */ + +/* Platform options */ +//#define POLARSSL_PLATFORM_STD_MEM_HDR /**< Header to include if POLARSSL_PLATFORM_NO_STD_FUNCTIONS is defined. Don't define if no header is needed. */ +//#define POLARSSL_PLATFORM_STD_MALLOC malloc /**< Default allocator to use, can be undefined */ +//#define POLARSSL_PLATFORM_STD_FREE free /**< Default free to use, can be undefined */ +//#define POLARSSL_PLATFORM_STD_PRINTF printf /**< Default printf to use, can be undefined */ +//#define POLARSSL_PLATFORM_STD_FPRINTF fprintf /**< Default fprintf to use, can be undefined */ + +/* SSL Cache options */ +//#define SSL_CACHE_DEFAULT_TIMEOUT 86400 /**< 1 day */ +//#define SSL_CACHE_DEFAULT_MAX_ENTRIES 50 /**< Maximum entries in cache */ + +/* SSL options */ +//#define SSL_MAX_CONTENT_LEN 16384 /**< Size of the input / output buffer */ +//#define SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ +//#define POLARSSL_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ + +/** + * Complete list of ciphersuites to use, in order of preference. + * + * \warning No dependency checking is done on that field! This option can only + * be used to restrict the set of available ciphersuites. It is your + * responsibility to make sure the needed modules are active. + * + * Use this to save a few hundred bytes of ROM (default ordering of all + * available ciphersuites) and a few to a few hundred bytes of RAM. + * + * The value below is only an example, not the default. + */ +//#define SSL_CIPHERSUITES TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + +/* Debug options */ +//#define POLARSSL_DEBUG_DFL_MODE POLARSSL_DEBUG_LOG_FULL /**< Default log: Full or Raw */ + +/* \} name SECTION: Module configuration options */ + +#include "check_config.h" + +#endif /* POLARSSL_CONFIG_H */ diff --git a/deps/polarssl/config12.h b/deps/polarssl/config12.h new file mode 100644 index 0000000..26fdf8b --- /dev/null +++ b/deps/polarssl/config12.h @@ -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 + * + * 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 + +#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 */ diff --git a/deps/polarssl/crypto-alt.txt b/deps/polarssl/crypto-alt.txt new file mode 100644 index 0000000..32fb2e6 --- /dev/null +++ b/deps/polarssl/crypto-alt.txt @@ -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 + diff --git a/deps/polarssl/dhm.patch b/deps/polarssl/dhm.patch new file mode 100644 index 0000000..43732f2 --- /dev/null +++ b/deps/polarssl/dhm.patch @@ -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) diff --git a/deps/polarssl/entropy-printf.patch b/deps/polarssl/entropy-printf.patch new file mode 100644 index 0000000..9a5b288 --- /dev/null +++ b/deps/polarssl/entropy-printf.patch @@ -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 + #endif + diff --git a/deps/polarssl/gitar b/deps/polarssl/gitar new file mode 100755 index 0000000..d340407 --- /dev/null +++ b/deps/polarssl/gitar @@ -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 diff --git a/deps/polarssl/intel_cpu.c b/deps/polarssl/intel_cpu.c new file mode 100644 index 0000000..fea1eda --- /dev/null +++ b/deps/polarssl/intel_cpu.c @@ -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); +} diff --git a/deps/polarssl/linux-arm.cmake b/deps/polarssl/linux-arm.cmake new file mode 100644 index 0000000..a356912 --- /dev/null +++ b/deps/polarssl/linux-arm.cmake @@ -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) diff --git a/deps/polarssl/polar-openssl.patch b/deps/polarssl/polar-openssl.patch new file mode 100644 index 0000000..9601b14 --- /dev/null +++ b/deps/polarssl/polar-openssl.patch @@ -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 + ++#include "config.h" ++ + #ifdef _MSC_VER + #include + 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 ++typedef UINT32 uint32_t; ++#else ++#include ++#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 + ++#include "config.h" ++ + #ifdef _MSC_VER + #include + 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 + ++#include "config.h" ++ + #ifdef _MSC_VER + #include + 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 + ++#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 + #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 + #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 + #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 + #include + 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 + #include + + int test_offset; diff --git a/deps/polarssl/polarssl-minicrypto.patch b/deps/polarssl/polarssl-minicrypto.patch new file mode 100644 index 0000000..0331ae1 --- /dev/null +++ b/deps/polarssl/polarssl-minicrypto.patch @@ -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 ++typedef UINT32 uint32_t; ++#else ++#include ++#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 diff --git a/deps/polarssl/ref b/deps/polarssl/ref new file mode 100644 index 0000000..6e16cdd --- /dev/null +++ b/deps/polarssl/ref @@ -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 diff --git a/deps/polarssl/ref-aesni b/deps/polarssl/ref-aesni new file mode 100644 index 0000000..0574500 --- /dev/null +++ b/deps/polarssl/ref-aesni @@ -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 diff --git a/deps/polarssl/relaxed-x509-date.patch b/deps/polarssl/relaxed-x509-date.patch new file mode 100644 index 0000000..eb021f2 --- /dev/null +++ b/deps/polarssl/relaxed-x509-date.patch @@ -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 + diff --git a/deps/polarssl/testpatch b/deps/polarssl/testpatch new file mode 100755 index 0000000..0330a9e --- /dev/null +++ b/deps/polarssl/testpatch @@ -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 diff --git a/deps/polarssl/unused/polarssl-const-ciphersuite.patch b/deps/polarssl/unused/polarssl-const-ciphersuite.patch new file mode 100644 index 0000000..62013cf --- /dev/null +++ b/deps/polarssl/unused/polarssl-const-ciphersuite.patch @@ -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; + } diff --git a/deps/polarssl/unused/polarssl-enum.patch b/deps/polarssl/unused/polarssl-enum.patch new file mode 100644 index 0000000..9dee1a1 --- /dev/null +++ b/deps/polarssl/unused/polarssl-enum.patch @@ -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; + } diff --git a/deps/polarssl/unused/polarssl-epki.patch b/deps/polarssl/unused/polarssl-epki.patch new file mode 100644 index 0000000..49ce2e5 --- /dev/null +++ b/deps/polarssl/unused/polarssl-epki.patch @@ -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 + + /** +@@ -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 + +@@ -235,4 +235,4 @@ + return( 0 ); + } + +-#endif /* defined(POLARSSL_PKCS11_C) */ ++#endif /* defined(POLARSSL_PKCS11_C) && !defined(POLARSSL_GENERIC_EXTERNAL_PRIVATE_KEY) */ diff --git a/deps/polarssl/unused/polarssl-invalid-mac.patch b/deps/polarssl/unused/polarssl-invalid-mac.patch new file mode 100644 index 0000000..7cc3799 --- /dev/null +++ b/deps/polarssl/unused/polarssl-invalid-mac.patch @@ -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 ) ); diff --git a/deps/polarssl/unused/trustex.patch b/deps/polarssl/unused/trustex.patch new file mode 100644 index 0000000..8605d1b --- /dev/null +++ b/deps/polarssl/unused/trustex.patch @@ -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 diff --git a/deps/snappy/build-snappy b/deps/snappy/build-snappy new file mode 100755 index 0000000..e05ff5f --- /dev/null +++ b/deps/snappy/build-snappy @@ -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 diff --git a/doc/openvpn-protocol-extensions.txt b/doc/openvpn-protocol-extensions.txt new file mode 100644 index 0000000..593fd04 --- /dev/null +++ b/doc/openvpn-protocol-extensions.txt @@ -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. diff --git a/docker-build.sh b/docker-build.sh new file mode 100755 index 0000000..97bbe21 --- /dev/null +++ b/docker-build.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +# build ovpn3-core with system-provided mbedtls and lz4 on various linux distros + +docker build -f dockerfiles/Dockerfile.debian -t deb . +docker run -it deb + +docker build -f dockerfiles/Dockerfile.ubu -t ubu . +docker run -it ubu + +docker build -f dockerfiles/Dockerfile.centos -t cnt . +docker run -it cnt diff --git a/dockerfiles/Dockerfile.centos b/dockerfiles/Dockerfile.centos new file mode 100644 index 0000000..32d1088 --- /dev/null +++ b/dockerfiles/Dockerfile.centos @@ -0,0 +1,19 @@ +FROM centos/devtoolset-7-toolchain-centos7 + +USER 0 +RUN yum -y update && yum -y install epel-release && \ + yum -y install -y mbedtls-devel lz4-devel git wget perl-Digest-SHA make + +ADD . /ovpn3/core + +ENV O3 /ovpn3/ +ENV DEP_DIR /ovpn3/deps +ENV DL /ovpn3/dl + +CMD mkdir $DEP_DIR && mkdir $DL && \ + /ovpn3/core/scripts/linux/build-all && \ + cd $O3/core/test/ovpncli && \ + ECHO=1 PROF=linux ASIO=1 MTLS_SYS=1 LZ4_SYS=1 NOSSL=1 $O3/core/scripts/build cli && \ + cd $O3/core/test/ssl && \ + ECHO=1 PROF=linux ASIO=1 MTLS_SYS=1 LZ4_SYS=1 NOSSL=1 $O3/core/scripts/build proto && \ + ./proto diff --git a/dockerfiles/Dockerfile.debian b/dockerfiles/Dockerfile.debian new file mode 100644 index 0000000..3aaceaa --- /dev/null +++ b/dockerfiles/Dockerfile.debian @@ -0,0 +1,17 @@ +FROM debian:9 + +RUN apt-get update && apt-get install -y autoconf build-essential wget git liblz4-dev libmbedtls-dev + +ADD . /ovpn3/core + +ENV O3 /ovpn3/ +ENV DEP_DIR /ovpn3/deps +ENV DL /ovpn3/dl + +CMD mkdir $DEP_DIR && mkdir $DL && \ + /ovpn3/core/scripts/linux/build-all && \ + cd $O3/core/test/ovpncli && \ + ECHO=1 PROF=linux ASIO=1 MTLS_SYS=1 LZ4_SYS=1 NOSSL=1 $O3/core/scripts/build cli && \ + cd $O3/core/test/ssl && \ + ECHO=1 PROF=linux ASIO=1 MTLS_SYS=1 LZ4_SYS=1 NOSSL=1 $O3/core/scripts/build proto && \ + ./proto diff --git a/dockerfiles/Dockerfile.ubu b/dockerfiles/Dockerfile.ubu new file mode 100644 index 0000000..1502a28 --- /dev/null +++ b/dockerfiles/Dockerfile.ubu @@ -0,0 +1,17 @@ +FROM ubuntu:16.04 + +RUN apt-get update && apt-get install -y autoconf build-essential wget git liblz4-dev libmbedtls-dev + +ADD . /ovpn3/core + +ENV O3 /ovpn3/ +ENV DEP_DIR /ovpn3/deps +ENV DL /ovpn3/dl + +CMD mkdir $DEP_DIR && mkdir $DL && \ + /ovpn3/core/scripts/linux/build-all && \ + cd $O3/core/test/ovpncli && \ + ECHO=1 PROF=linux ASIO=1 MTLS_SYS=1 LZ4_SYS=1 NOSSL=1 $O3/core/scripts/build cli && \ + cd $O3/core/test/ssl && \ + ECHO=1 PROF=linux ASIO=1 MTLS_SYS=1 LZ4_SYS=1 NOSSL=1 $O3/core/scripts/build proto && \ + ./proto diff --git a/javacli/.gitignore b/javacli/.gitignore new file mode 100644 index 0000000..2ae5f45 --- /dev/null +++ b/javacli/.gitignore @@ -0,0 +1,7 @@ +build +ovpncli_wrap.cxx +ovpncli_wrap.h +ovpncli.java +ovpncliJNI.java +ClientAPI_*.java +SWIGTYPE_*.java diff --git a/javacli/Client.java b/javacli/Client.java new file mode 100644 index 0000000..b351789 --- /dev/null +++ b/javacli/Client.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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +// 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; + } + } diff --git a/javacli/Main.java b/javacli/Main.java new file mode 100644 index 0000000..99936ea --- /dev/null +++ b/javacli/Main.java @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +// 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 [username] [password]"); + System.exit(2); + } + } +} diff --git a/javacli/OpenVPNClientThread.java b/javacli/OpenVPNClientThread.java new file mode 100644 index 0000000..269a22c --- /dev/null +++ b/javacli/OpenVPNClientThread.java @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +// 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); + } +} diff --git a/javacli/android/cpu.cpp b/javacli/android/cpu.cpp new file mode 100644 index 0000000..33fd3bb --- /dev/null +++ b/javacli/android/cpu.cpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#include +#include +#include + +#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; +} diff --git a/javacli/android/jellybean_hack.cpp b/javacli/android/jellybean_hack.cpp new file mode 100644 index 0000000..d9c0d4c --- /dev/null +++ b/javacli/android/jellybean_hack.cpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +// Native companion code for JellyBeanHack.java + +#include +#include +#include + +#include + +#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(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(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); + } +} diff --git a/javacli/build-android b/javacli/build-android new file mode 100755 index 0000000..2fcfa40 --- /dev/null +++ b/javacli/build-android @@ -0,0 +1,126 @@ +#!/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 + +TARGETS=${TARGETS:-android-a7a android-a8a android-x86} + +for TARGET in $TARGETS; 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 + +[ -z "$GPP_CMD" ] && GPP_CMD=g++ + +echo CORE $ABI +$GPP_CMD \ + $CXX_COMPILER_FLAGS \ + $PLATFORM_FLAGS \ + $OTHER_COMPILER_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 \ + -DOPENVPN_USE_TLS_MD5 \ + -DASIO_HAS_STD_STRING_VIEW \ + -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 +$GPP_CMD \ + $CXX_COMPILER_FLAGS \ + $PLATFORM_FLAGS \ + $OTHER_COMPILER_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_wrap.cxx ovpncli_wrap.h ovpncli.java ovpncliJNI.java SWIGTYPE_*.java ClientAPI_*.java build/ +git clean -q -fX . + +tar -czf android-core-build.tgz build +mv android-core-build.tgz $O3/ diff --git a/javacli/build-linux b/javacli/build-linux new file mode 100755 index 0000000..d0e37a1 --- /dev/null +++ b/javacli/build-linux @@ -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 -Werror -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 -Werror \ + $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 diff --git a/javacli/ovpncli.i b/javacli/ovpncli.i new file mode 100644 index 0000000..0671a6d --- /dev/null +++ b/javacli/ovpncli.i @@ -0,0 +1,55 @@ +// 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 these ClientAPI::OpenVPNClient bases +%ignore openvpn::ClientAPI::LogReceiver; +%ignore openvpn::ExternalTun::Factory; +%ignore openvpn::ExternalTransport::Factory; + +// 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; + %template(ClientAPI_LLVector) vector; + %template(ClientAPI_StringVec) vector; +}; + +// interface to be bridged between C++ and target language +%include "openvpn/pki/epkibase.hpp" +%include "openvpn/tun/builder/base.hpp" +%import "openvpn/tun/extern/fw.hpp" // ignored +%import "openvpn/transport/client/extern/fw.hpp" // ignored +%include "ovpncli.hpp" diff --git a/mac/.gitignore b/mac/.gitignore new file mode 100644 index 0000000..14ce7f3 --- /dev/null +++ b/mac/.gitignore @@ -0,0 +1 @@ +**/xcuserdata/ diff --git a/mac/ovpn3-core/ovpn3-core.xcodeproj/project.pbxproj b/mac/ovpn3-core/ovpn3-core.xcodeproj/project.pbxproj new file mode 100644 index 0000000..4df459d --- /dev/null +++ b/mac/ovpn3-core/ovpn3-core.xcodeproj/project.pbxproj @@ -0,0 +1,342 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + DF380AE2201F0A2F0003272D /* cli.cpp in Sources */ = {isa = PBXBuildFile; fileRef = DF380AE1201F0A2F0003272D /* cli.cpp */; }; + DF380AE5201F0D4F0003272D /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DF380AE4201F0D4F0003272D /* CoreFoundation.framework */; }; + DF380AE7201F0D910003272D /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DF380AE6201F0D910003272D /* SystemConfiguration.framework */; }; + DF380AE9201F0DB80003272D /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DF380AE8201F0DB80003272D /* IOKit.framework */; }; + DF380AEB201F0DDC0003272D /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DF380AEA201F0DDC0003272D /* CoreServices.framework */; }; + DF380AED201F0E0E0003272D /* libmbedtls.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DF380AEC201F0E0E0003272D /* libmbedtls.a */; }; + DF838B412090AC2F00B68F90 /* liblz4.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DF838B402090AC2F00B68F90 /* liblz4.a */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + DF380AD4201F07AE0003272D /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + DF380AD6201F07AE0003272D /* ovpn3-core */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "ovpn3-core"; sourceTree = BUILT_PRODUCTS_DIR; }; + DF380AE0201F09B70003272D /* openvpn */ = {isa = PBXFileReference; lastKnownFileType = folder; name = openvpn; path = ../../../openvpn; sourceTree = ""; }; + DF380AE1201F0A2F0003272D /* cli.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = cli.cpp; path = ../../../test/ovpncli/cli.cpp; sourceTree = ""; }; + DF380AE4201F0D4F0003272D /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; + DF380AE6201F0D910003272D /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; + DF380AE8201F0DB80003272D /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; + DF380AEA201F0DDC0003272D /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; }; + DF380AEC201F0E0E0003272D /* libmbedtls.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmbedtls.a; path = "../../../deps/mbedtls/mbedtls-osx/library/libmbedtls.a"; sourceTree = ""; }; + DF838B402090AC2F00B68F90 /* liblz4.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = liblz4.a; path = "../../../deps/lz4/lz4-osx/lib/liblz4.a"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + DF380AD3201F07AE0003272D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + DF838B412090AC2F00B68F90 /* liblz4.a in Frameworks */, + DF380AED201F0E0E0003272D /* libmbedtls.a in Frameworks */, + DF380AEB201F0DDC0003272D /* CoreServices.framework in Frameworks */, + DF380AE9201F0DB80003272D /* IOKit.framework in Frameworks */, + DF380AE7201F0D910003272D /* SystemConfiguration.framework in Frameworks */, + DF380AE5201F0D4F0003272D /* CoreFoundation.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + DF380ACD201F07AE0003272D = { + isa = PBXGroup; + children = ( + DF380AD8201F07AE0003272D /* ovpn3-core */, + DF380AD7201F07AE0003272D /* Products */, + DF380AE3201F0D4F0003272D /* Frameworks */, + ); + sourceTree = ""; + }; + DF380AD7201F07AE0003272D /* Products */ = { + isa = PBXGroup; + children = ( + DF380AD6201F07AE0003272D /* ovpn3-core */, + ); + name = Products; + sourceTree = ""; + }; + DF380AD8201F07AE0003272D /* ovpn3-core */ = { + isa = PBXGroup; + children = ( + DF380AE1201F0A2F0003272D /* cli.cpp */, + DF380AE0201F09B70003272D /* openvpn */, + ); + path = "ovpn3-core"; + sourceTree = ""; + }; + DF380AE3201F0D4F0003272D /* Frameworks */ = { + isa = PBXGroup; + children = ( + DF838B402090AC2F00B68F90 /* liblz4.a */, + DF380AEC201F0E0E0003272D /* libmbedtls.a */, + DF380AEA201F0DDC0003272D /* CoreServices.framework */, + DF380AE8201F0DB80003272D /* IOKit.framework */, + DF380AE6201F0D910003272D /* SystemConfiguration.framework */, + DF380AE4201F0D4F0003272D /* CoreFoundation.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + DF380AD5201F07AE0003272D /* ovpn3-core */ = { + isa = PBXNativeTarget; + buildConfigurationList = DF380ADD201F07AE0003272D /* Build configuration list for PBXNativeTarget "ovpn3-core" */; + buildPhases = ( + DF380AD2201F07AE0003272D /* Sources */, + DF380AD3201F07AE0003272D /* Frameworks */, + DF380AD4201F07AE0003272D /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "ovpn3-core"; + productName = "ovpn3-core"; + productReference = DF380AD6201F07AE0003272D /* ovpn3-core */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + DF380ACE201F07AE0003272D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0920; + ORGANIZATIONNAME = "Lev Stipakov"; + TargetAttributes = { + DF380AD5201F07AE0003272D = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = DF380AD1201F07AE0003272D /* Build configuration list for PBXProject "ovpn3-core" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = DF380ACD201F07AE0003272D; + productRefGroup = DF380AD7201F07AE0003272D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + DF380AD5201F07AE0003272D /* ovpn3-core */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + DF380AD2201F07AE0003272D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DF380AE2201F0A2F0003272D /* cli.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + DF380ADB201F07AE0003272D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + DF380ADC201F07AE0003272D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.13; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + }; + name = Release; + }; + DF380ADE201F07AE0003272D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + GCC_PREPROCESSOR_DEFINITIONS = ( + USE_ASIO, + ASIO_STANDALONE, + USE_MBEDTLS, + HAVE_LZ4, + LZ4_DISABLE_DEPRECATE_WARNINGS, + ); + HEADER_SEARCH_PATHS = ( + "\"$(SRCROOT)/../..\"", + "\"$(SRCROOT)/../../../deps/asio/asio/include\"", + "\"$(SRCROOT)/../../../deps/mbedtls/mbedtls-osx/include\"", + "\"$(SRCROOT)/../../../deps/lz4/lz4-osx/include\"", + ); + LIBRARY_SEARCH_PATHS = ( + "\"$(SRCROOT)/../../../deps/mbedtls/mbedtls-osx/library\"", + "\"$(SRCROOT)/../../../deps/lz4/lz4-osx/lib\"", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + STRINGS_FILE_OUTPUT_ENCODING = "UTF-8"; + }; + name = Debug; + }; + DF380ADF201F07AE0003272D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + GCC_PREPROCESSOR_DEFINITIONS = ( + USE_ASIO, + ASIO_STANDALONE, + USE_MBEDTLS, + HAVE_LZ4, + LZ4_DISABLE_DEPRECATE_WARNINGS, + ); + HEADER_SEARCH_PATHS = ( + "\"$(SRCROOT)/../..\"", + "\"$(SRCROOT)/../../../deps/asio/asio/include\"", + "\"$(SRCROOT)/../../../deps/mbedtls/mbedtls-osx/include\"", + "\"$(SRCROOT)/../../../deps/lz4/lz4-osx/include\"", + ); + LIBRARY_SEARCH_PATHS = ( + "\"$(SRCROOT)/../../../deps/mbedtls/mbedtls-osx/library\"", + "\"$(SRCROOT)/../../../deps/lz4/lz4-osx/lib\"", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + STRINGS_FILE_OUTPUT_ENCODING = "UTF-8"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + DF380AD1201F07AE0003272D /* Build configuration list for PBXProject "ovpn3-core" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DF380ADB201F07AE0003272D /* Debug */, + DF380ADC201F07AE0003272D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + DF380ADD201F07AE0003272D /* Build configuration list for PBXNativeTarget "ovpn3-core" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DF380ADE201F07AE0003272D /* Debug */, + DF380ADF201F07AE0003272D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = DF380ACE201F07AE0003272D /* Project object */; +} diff --git a/mac/ovpn3-core/ovpn3-core.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/mac/ovpn3-core/ovpn3-core.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1595398 --- /dev/null +++ b/mac/ovpn3-core/ovpn3-core.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/openvpn/addr/addrlist.hpp b/openvpn/addr/addrlist.hpp new file mode 100644 index 0000000..0db21d8 --- /dev/null +++ b/openvpn/addr/addrlist.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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_ADDR_ADDRLIST_H +#define OPENVPN_ADDR_ADDRLIST_H + +#include +#include + +namespace openvpn { + namespace IP { + + // A list of unique IP addresses + class AddrList : public std::vector, public RC + { + public: + typedef RCPtr 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 diff --git a/openvpn/addr/addrpair.hpp b/openvpn/addr/addrpair.hpp new file mode 100644 index 0000000..b8bfc1e --- /dev/null +++ b/openvpn/addr/addrpair.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_ADDR_ADDRPAIR_H +#define OPENVPN_ADDR_ADDRPAIR_H + +#include + +#include +#include +#include +#include + +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(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(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(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 diff --git a/openvpn/addr/addrspacesplit.hpp b/openvpn/addr/addrspacesplit.hpp new file mode 100644 index 0000000..8edfa2b --- /dev/null +++ b/openvpn/addr/addrspacesplit.hpp @@ -0,0 +1,109 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +// Invert a route list. Used to support excluded routes on platforms that +// don't support them natively. + +#pragma once + +#include +#include + +namespace openvpn { + namespace IP { + class AddressSpaceSplitter : public RouteList + { + public: + OPENVPN_EXCEPTION(address_space_splitter); + + AddressSpaceSplitter() {} + + // NOTE: when passing AddressSpaceSplitter to this constructor, make sure + // to static_cast it to RouteList& so as to avoid matching the + // default copy constructor. + explicit AddressSpaceSplitter(const RouteList& in) + : AddressSpaceSplitter(in, in.version_mask()) + { + } + + AddressSpaceSplitter(const RouteList& in, const Addr::VersionMask vermask) + { + in.verify_canonical(); + if (vermask & Addr::V4_MASK) + descend(in, Route(Addr::from_zero(Addr::V4), 0)); + if (vermask & Addr::V6_MASK) + descend(in, Route(Addr::from_zero(Addr::V6), 0)); + } + + private: + enum Type { + EQUAL, + SUBROUTE, + LEAF, + }; + /** + * This method construct a non-overlapping list of routes spanning the address + * space in @param route. The routes are constructed in a way that each + * route in the returned list is smaller or equalto each route in + * parameter @param in + * + * @param route The route we currently are looking at and split if it does + * not meet the requirements + */ + void descend(const RouteList& in, const Route& route) + { + switch (find(in, route)) + { + case SUBROUTE: + { + Route r1, r2; + if (route.split(r1, r2)) + { + descend(in, r1); + descend(in, r2); + } + else + push_back(route); + break; + } + case EQUAL: + case LEAF: + push_back(route); + 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) + type = EQUAL; + else if (route.contains(r)) + return SUBROUTE; + } + return type; + } + }; + } +} diff --git a/openvpn/addr/ip.hpp b/openvpn/addr/ip.hpp new file mode 100644 index 0000000..cd14e5c --- /dev/null +++ b/openvpn/addr/ip.hpp @@ -0,0 +1,992 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_ADDR_IP_H +#define OPENVPN_ADDR_IP_H + +#include +#include // for std::memset + +#include + +#include +#include +#include +#include +#include +#include +#include + +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)) + { + } + +#ifndef SWIGPYTHON + // When calling IP:Addr with None as the second parameter, Swig will + // always pick this function and complain about not being able to convert + // a null pointer to a const std::string reference. Hide this function, so + // swig is forced to take the const char* variant of this function instead + Addr(const std::string& ipstr, const std::string& title, Version required_version = UNSPEC) + : Addr(from_string(ipstr, title.c_str(), required_version)) + { + } +#endif + + 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")); + } + +#ifndef SWIGPYTHON + void validate_version(const std::string& title, Version required_version) const + { + validate_version(title.c_str(), required_version); + } +#endif + + 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(); + } + +#ifndef SWIGPYTHON + static std::string validate(const std::string& ipstr, const std::string& title, Version required_version = UNSPEC) + { + return validate(ipstr, title.c_str(), required_version); + } +#endif + + 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(IPv4::Addr addr) + { + Addr a; + a.ver = V4; + a.u.v4 = std::move(addr); + return a; + } + + static Addr from_ipv6(IPv6::Addr addr) + { + Addr a; + a.ver = V6; + a.u.v6 = std::move(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 = V6; + 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"); + } + + // validate the prefix length for the IP version + static bool validate_prefix_len(Version v, const unsigned int prefix_len) + { + if (v == V4) + { + if (prefix_len <= V4_SIZE) + return true; + } + else if (v == V6) + { + if (prefix_len <= V6_SIZE) + return true; + } + return false; + } + + // 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; + } + + template + void hash(HASH& h) const + { + switch (ver) + { + case Addr::V4: + u.v4.hash(h); + break; + case Addr::V6: + u.v6.hash(h); + break; + default: + break; + } + } + +#ifdef HAVE_CITYHASH + std::size_t hashval() const + { + HashSizeT h; + hash(h); + return h.value(); + } +#endif + +#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) + } +} + +#ifdef HAVE_CITYHASH +OPENVPN_HASH_METHOD(openvpn::IP::Addr, hashval); +#endif + +#endif diff --git a/openvpn/addr/iperr.hpp b/openvpn/addr/iperr.hpp new file mode 100644 index 0000000..fa9af11 --- /dev/null +++ b/openvpn/addr/iperr.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_ADDR_IPERR_H +#define OPENVPN_ADDR_IPERR_H + +#include + +#include + +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 diff --git a/openvpn/addr/ipv4.hpp b/openvpn/addr/ipv4.hpp new file mode 100644 index 0000000..1fd55de --- /dev/null +++ b/openvpn/addr/ipv4.hpp @@ -0,0 +1,588 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_ADDR_IPV4_H +#define OPENVPN_ADDR_IPV4_H + +#include // for std::memcpy, std::memset +#include +#include // for std::uint32_t + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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; + + bool defined() const + { + return true; + } + + 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 unsigned short port=0) const + { + struct sockaddr_in ret; + std::memset(&ret, 0, sizeof(ret)); + ret.sin_family = AF_INET; + ret.sin_port = htons(port); + 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; + } + + template + void hash(HASH& h) const + { + h(u.addr); + } + +#ifdef HAVE_CITYHASH + std::size_t hashval() const + { + HashSizeT h; + hash(h); + return h.value(); + } +#endif + +#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) + } +} + +#ifdef HAVE_CITYHASH +OPENVPN_HASH_METHOD(openvpn::IPv4::Addr, hashval); +#endif + +#endif // OPENVPN_ADDR_IPV4_H diff --git a/openvpn/addr/ipv6.hpp b/openvpn/addr/ipv6.hpp new file mode 100644 index 0000000..d116934 --- /dev/null +++ b/openvpn/addr/ipv6.hpp @@ -0,0 +1,847 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_ADDR_IPV6_H +#define OPENVPN_ADDR_IPV6_H + +#include // for std::memcpy, std::memset +#include // for std::min +#include // for std::uint32_t + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 }; + + bool defined() const + { + return true; + } + + 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 unsigned short port=0) const + { + struct sockaddr_in6 ret; + std::memset(&ret, 0, sizeof(ret)); + ret.sin6_family = AF_INET6; + ret.sin6_port = htons(port); + 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)<= 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; + } + + template + void hash(HASH& h) const + { + h(u.bytes, sizeof(u.bytes)); + } + +#ifdef HAVE_CITYHASH + std::size_t hashval() const + { + HashSizeT h; + hash(h); + return h.value(); + } +#endif + +#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)<>= 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) + } +} + +#ifdef HAVE_CITYHASH +OPENVPN_HASH_METHOD(openvpn::IPv6::Addr, hashval); +#endif + +#endif // OPENVPN_ADDR_IPV6_H diff --git a/openvpn/addr/macaddr.hpp b/openvpn/addr/macaddr.hpp new file mode 100644 index 0000000..d2e9b69 --- /dev/null +++ b/openvpn/addr/macaddr.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_ADDR_MACADDR_H +#define OPENVPN_ADDR_MACADDR_H + +#include +#include +#include + +#include +#include +#include + +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 diff --git a/openvpn/addr/pool.hpp b/openvpn/addr/pool.hpp new file mode 100644 index 0000000..b176f5d --- /dev/null +++ b/openvpn/addr/pool.hpp @@ -0,0 +1,164 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_ADDR_POOL_H +#define OPENVPN_ADDR_POOL_H + +#include +#include +#include +#include + +#include +#include + +#include +#include + +namespace openvpn { + namespace IP { + + // Maintain a pool of IP addresses. + // A should be IP::Addr, IPv4::Addr, or IPv6::Addr. + template + class PoolType + { + public: + PoolType() {} + + // Add range of addresses to pool (pool will own the addresses). + void add_range(const RangeType& range) + { + auto 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) + { + auto 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(); + } + + // Return number of pool addresses currently in use. + size_t n_free() const + { + return 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) + { + freelist_fill(); + if (freelist.empty()) + return false; + const ADDR& a = freelist.front(); + auto 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) + { + auto 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) + { + auto 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(); } + + // Override to refill freelist on demand + virtual void freelist_fill() + { + } + + std::string to_string() const + { + std::string ret; + for (const auto& e : map) + { + if (e.second) + { + ret += e.first.to_string(); + ret += '\n'; + } + } + return ret; + } + + private: + std::deque freelist; + std::unordered_map map; + }; + + typedef PoolType Pool; + } +} + +#endif diff --git a/openvpn/addr/quoteip.hpp b/openvpn/addr/quoteip.hpp new file mode 100644 index 0000000..cab2b8b --- /dev/null +++ b/openvpn/addr/quoteip.hpp @@ -0,0 +1,36 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#pragma once + +#include + +namespace openvpn { + + // return ip_addr in brackets if it is IPv6 + std::string quote_ip(const std::string& ip_addr) + { + if (ip_addr.find(':') != std::string::npos) + return '[' + ip_addr + ']'; + else + return ip_addr; + } +} diff --git a/openvpn/addr/randaddr.hpp b/openvpn/addr/randaddr.hpp new file mode 100644 index 0000000..e8cdac5 --- /dev/null +++ b/openvpn/addr/randaddr.hpp @@ -0,0 +1,68 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#pragma once + +#include +#include +#include + +namespace openvpn { + namespace IP { + + inline IPv4::Addr random_addr_v4(RandomAPI& prng) + { + return IPv4::Addr::from_uint32(prng.rand_get()); + } + + inline IPv6::Addr random_addr_v6(RandomAPI& prng) + { + unsigned char bytes[16]; + prng.rand_fill(bytes); + return IPv6::Addr::from_byte_string(bytes); + } + + inline Addr random_addr(const Addr::Version v, RandomAPI& prng) + { + switch (v) + { + case Addr::V4: + return Addr::from_ipv4(random_addr_v4(prng)); + case Addr::V6: + return Addr::from_ipv6(random_addr_v6(prng)); + default: + throw ip_exception("address unspecified"); + } + } + + // bit positions between templ.prefix_len and prefix_len are randomized + inline Route random_subnet(const Route& templ, + const unsigned int prefix_len, + RandomAPI& prng) + { + if (!templ.is_canonical()) + throw Exception("IP::random_subnet: template route not canonical: " + templ.to_string()); + return Route(((random_addr(templ.addr.version(), prng) & ~templ.netmask()) | templ.addr) + & Addr::netmask_from_prefix_len(templ.addr.version(), prefix_len), + prefix_len); + } + } +} diff --git a/openvpn/addr/range.hpp b/openvpn/addr/range.hpp new file mode 100644 index 0000000..8feaf74 --- /dev/null +++ b/openvpn/addr/range.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_ADDR_RANGE_H +#define OPENVPN_ADDR_RANGE_H + +#include +#include + +#include +#include + +#include + +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 + 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 + class RangePartitionType + { + public: + RangePartitionType(const RangeType& src_range, const size_t n_partitions) + : range(src_range), + remaining(n_partitions) + { + } + + bool next(RangeType& 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 range; + size_t remaining; + }; + + typedef RangeType Range; + typedef RangePartitionType RangePartition; + } +} + +#endif diff --git a/openvpn/addr/regex.hpp b/openvpn/addr/regex.hpp new file mode 100644 index 0000000..049b9fb --- /dev/null +++ b/openvpn/addr/regex.hpp @@ -0,0 +1,59 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +// 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 + +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 diff --git a/openvpn/addr/route.hpp b/openvpn/addr/route.hpp new file mode 100644 index 0000000..d67c0d8 --- /dev/null +++ b/openvpn/addr/route.hpp @@ -0,0 +1,344 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_ADDR_ROUTE_H +#define OPENVPN_ADDR_ROUTE_H + +#include +#include +#include +#include // for std::uint32_t +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace openvpn { + namespace IP { + // Basic route object + template + class RouteType + { + public: + 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 pair; + pair.reserve(2); + Split::by_char_void, 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(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; + } + + bool defined() const + { + return addr.defined(); + } + + IP::Addr::Version version() const + { + return addr.version(); + } + + IP::Addr::VersionMask version_mask() const + { + return addr.version_mask(); + } + + RouteType to_ipv4() const + { + return RouteType(addr.to_ipv4(), prefix_len); + } + + RouteType to_ipv6() const + { + return RouteType(addr.to_ipv6(), prefix_len); + } + + ADDR netmask() const + { + return netmask_(addr, 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(); + } + + void verify_canonical() const + { + if (!is_canonical()) + throw route_error("route not canonical: " + to_string()); + } + + bool is_host() const + { + return addr.defined() && prefix_len == addr.size(); + } + + unsigned int host_bits() const + { + if (prefix_len < addr.size()) + return addr.size() - prefix_len; + else + return 0; + } + + bool contains(const ADDR& a) const // assumes canonical address/routes + { + if (addr.defined() && version_eq(addr, a)) + 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 + netmask_(addr, 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 std::tie(prefix_len, addr) == std::tie(other.prefix_len, other.addr); + } + + bool operator!=(const RouteType& other) const + { + return std::tie(prefix_len, addr) != std::tie(other.prefix_len, other.addr); + } + + bool operator<(const RouteType& other) const + { + return std::tie(prefix_len, addr) < std::tie(other.prefix_len, other.addr); + } + + template + void hash(HASH& h) const + { + addr.hash(h); + h(prefix_len); + } + +#ifdef HAVE_CITYHASH + std::size_t hash_value() const + { + HashSizeT h; + hash(h); + return h.value(); + } +#endif + + private: + static IPv4::Addr netmask_(const IPv4::Addr&, unsigned int prefix_len) + { + return IPv4::Addr::netmask_from_prefix_len(prefix_len); + } + + static IPv6::Addr netmask_(const IPv6::Addr&, unsigned int prefix_len) + { + return IPv6::Addr::netmask_from_prefix_len(prefix_len); + } + + static IP::Addr netmask_(const IP::Addr& addr, unsigned int prefix_len) + { + return IP::Addr::netmask_from_prefix_len(addr.version(), prefix_len); + } + + static bool version_eq(const IPv4::Addr&, const IPv4::Addr&) + { + return true; + } + + static bool version_eq(const IPv6::Addr&, const IPv6::Addr&) + { + return true; + } + + static bool version_eq(const IP::Addr& a1, const IP::Addr& a2) + { + return a1.version() == a2.version(); + } + }; + + template + struct RouteTypeList : public std::vector> + { + typedef std::vector< RouteType > 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) + r.verify_canonical(); + } + + template + bool contains(const R& c) const + { + for (auto &r : *this) + if (r.contains(c)) + return true; + return false; + } + }; + + typedef RouteType Route; + typedef RouteType Route4; + typedef RouteType Route6; + + typedef RouteTypeList RouteList; + typedef RouteTypeList Route4List; + typedef RouteTypeList 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; + } + } +} + +#ifdef HAVE_CITYHASH +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 + +#endif diff --git a/openvpn/apple/cf/cf.hpp b/openvpn/apple/cf/cf.hpp new file mode 100644 index 0000000..f5e9e87 --- /dev/null +++ b/openvpn/apple/cf/cf.hpp @@ -0,0 +1,459 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_APPLECRYPTO_CF_CF_H +#define OPENVPN_APPLECRYPTO_CF_CF_H + +#include +#include +#include +#include +#include +#include + +#include + +// Wrapper classes for Apple Core Foundation objects. + +#define OPENVPN_CF_WRAP(cls, castmeth, cftype, idmeth) \ + template <> \ + struct Type \ + { \ + static CFTypeRef cast(CFTypeRef obj) \ + { \ + if (obj && CFGetTypeID(obj) == idmeth()) \ + return obj; \ + else \ + return nullptr; \ + } \ + }; \ + typedef Wrap cls; \ + inline cls castmeth(CFTypeRef obj) \ + { \ + CFTypeRef o = Type::cast(obj); \ + if (o) \ + return cls(cftype(o), GET); \ + else \ + return cls(); \ + } + +namespace openvpn { + namespace CF + { + enum Rule { + CREATE, // create rule + GET // get rule + }; + + template struct Type {}; + + template + class Wrap + { + public: + Wrap() : obj_(nullptr) {} + + explicit Wrap(T obj, const Rule rule=CREATE) + { + if (rule == GET && 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 Rule rule=CREATE) + { + if (rule == GET && obj) + CFRetain(obj); + if (obj_) + CFRelease(obj_); + obj_ = obj; + } + + bool defined() const { return obj_ != nullptr; } + + explicit operator bool() const noexcept + { + return defined(); + } + + T operator()() const { return obj_; } + + CFTypeRef generic() const { return (CFTypeRef)obj_; } + + static T cast(CFTypeRef obj) { return T(Type::cast(obj)); } + + static Wrap from_generic(CFTypeRef obj, const Rule rule=CREATE) + { + return Wrap(cast(obj), rule); + } + + 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 create-rule 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) = delete; // prevent use because no way to pass rule parameter + + T obj_; + }; + + // 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 Generic; + + inline Generic generic_cast(CFTypeRef obj) + { + return Generic(obj, GET); + } + + // constructors + + inline String string(const char *str) + { + return String(CFStringCreateWithCString(kCFAllocatorDefault, str, kCFStringEncodingUTF8)); + } + + inline String string(CFStringRef str) + { + return String(str, GET); + } + + 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 Dict dict(const void **keys, const void **values, CFIndex numValues) + { + return Dict(CFDictionaryCreate(kCFAllocatorDefault, + keys, + values, + numValues, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks)); + } + + inline Dict const_dict(MutableDict& mdict) + { + return Dict(mdict(), CF::GET); + } + + inline Array const_array(MutableArray& marray) + { + return Array(marray(), CF::GET); + } + + 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 + 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 + inline CFIndex array_len(const ARRAY& array) + { + if (array.defined()) + return CFArrayGetCount(array()); + else + return 0; + } + + template + inline CFIndex dict_len(const DICT& dict) + { + if (dict.defined()) + return CFDictionaryGetCount(dict()); + else + return 0; + } + + template + inline CFTypeRef array_index(const ARRAY& array, const CFIndex idx) + { + if (array.defined() && CFArrayGetCount(array()) > idx) + return CFArrayGetValueAtIndex(array(), idx); + else + return nullptr; + } + + template + 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 + + struct cppstring_error : public std::exception + { + virtual const char* what() const throw() + { + return "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 + 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 diff --git a/openvpn/apple/cf/cfhelper.hpp b/openvpn/apple/cf/cfhelper.hpp new file mode 100644 index 0000000..4c8d336 --- /dev/null +++ b/openvpn/apple/cf/cfhelper.hpp @@ -0,0 +1,261 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_APPLECRYPTO_CF_CFHELPER_H +#define OPENVPN_APPLECRYPTO_CF_CFHELPER_H + +#include +#include + +// 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 { + + // essentially a vector of void *, used as source for array and dictionary constructors + typedef BufferAllocatedType SrcList; + + inline Array array(const SrcList& values) + { + return array((const void **)values.c_data(), values.size()); + } + + 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 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 diff --git a/openvpn/apple/cf/cfhost.hpp b/openvpn/apple/cf/cfhost.hpp new file mode 100644 index 0000000..ab51494 --- /dev/null +++ b/openvpn/apple/cf/cfhost.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_APPLECRYPTO_CF_CFHOST_H +#define OPENVPN_APPLECRYPTO_CF_CFHOST_H + +#include + +namespace openvpn { + namespace CF { + OPENVPN_CF_WRAP(Host, host_cast, CFHostRef, CFHostGetTypeID) + } +} + +#endif diff --git a/openvpn/apple/cf/cfrunloop.hpp b/openvpn/apple/cf/cfrunloop.hpp new file mode 100644 index 0000000..777af0c --- /dev/null +++ b/openvpn/apple/cf/cfrunloop.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_APPLECRYPTO_CF_CFRUNLOOP_H +#define OPENVPN_APPLECRYPTO_CF_CFRUNLOOP_H + +#include + +namespace openvpn { + namespace CF { + OPENVPN_CF_WRAP(RunLoop, runloop_cast, CFRunLoopRef, CFRunLoopGetTypeID) + OPENVPN_CF_WRAP(RunLoopSource, runloop_source_cast, CFRunLoopSourceRef, CFRunLoopSourceGetTypeID); + } +} + +#endif diff --git a/openvpn/apple/cf/cfsec.hpp b/openvpn/apple/cf/cfsec.hpp new file mode 100644 index 0000000..87da3e5 --- /dev/null +++ b/openvpn/apple/cf/cfsec.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_APPLECRYPTO_CF_CFSEC_H +#define OPENVPN_APPLECRYPTO_CF_CFSEC_H + +#include + +#include +#include +#include +#include + +#ifndef OPENVPN_PLATFORM_IPHONE +#include +#include +#endif + +#include +#include +#include + +// 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 diff --git a/openvpn/apple/cf/cfsocket.hpp b/openvpn/apple/cf/cfsocket.hpp new file mode 100644 index 0000000..285114f --- /dev/null +++ b/openvpn/apple/cf/cfsocket.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_APPLECRYPTO_CF_CFSTREAM_H +#define OPENVPN_APPLECRYPTO_CF_CFSTREAM_H + +#include + +namespace openvpn { + namespace CF { + OPENVPN_CF_WRAP(Socket, socket_cast, CFSocketRef, CFSocketGetTypeID) + } +} + +#endif diff --git a/openvpn/apple/cf/cfstream.hpp b/openvpn/apple/cf/cfstream.hpp new file mode 100644 index 0000000..7976190 --- /dev/null +++ b/openvpn/apple/cf/cfstream.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_APPLECRYPTO_CF_CFSTREAM_H +#define OPENVPN_APPLECRYPTO_CF_CFSTREAM_H + +#include + +namespace openvpn { + namespace CF { + OPENVPN_CF_WRAP(ReadStream, read_stream_cast, CFReadStreamRef, CFReadStreamGetTypeID) + OPENVPN_CF_WRAP(WriteStream, write_stream_cast, CFWriteStreamRef, CFWriteStreamGetTypeID) + } +} + +#endif diff --git a/openvpn/apple/cf/cftimer.hpp b/openvpn/apple/cf/cftimer.hpp new file mode 100644 index 0000000..5acc7ec --- /dev/null +++ b/openvpn/apple/cf/cftimer.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_APPLECRYPTO_CF_CFTIMER_H +#define OPENVPN_APPLECRYPTO_CF_CFTIMER_H + +#include + +namespace openvpn { + namespace CF { + OPENVPN_CF_WRAP(Timer, timer_cast, CFRunLoopTimerRef, CFRunLoopTimerGetTypeID) + } +} + +#endif diff --git a/openvpn/apple/cf/error.hpp b/openvpn/apple/cf/error.hpp new file mode 100644 index 0000000..ca087a0 --- /dev/null +++ b/openvpn/apple/cf/error.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_APPLECRYPTO_CF_ERROR_H +#define OPENVPN_APPLECRYPTO_CF_ERROR_H + +#include + +#include + +#include + +// 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 diff --git a/openvpn/apple/iosactiveiface.hpp b/openvpn/apple/iosactiveiface.hpp new file mode 100644 index 0000000..91d0b29 --- /dev/null +++ b/openvpn/apple/iosactiveiface.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#include + +#include +#include + +#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 diff --git a/openvpn/apple/maclife.hpp b/openvpn/apple/maclife.hpp new file mode 100644 index 0000000..e1a32ec --- /dev/null +++ b/openvpn/apple/maclife.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_APPLE_MACLIFE_H +#define OPENVPN_APPLE_MACLIFE_H + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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::GET); + 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 exception: " << 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 diff --git a/openvpn/apple/macsleep.hpp b/openvpn/apple/macsleep.hpp new file mode 100644 index 0000000..eeaa6d7 --- /dev/null +++ b/openvpn/apple/macsleep.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_APPLE_MACSLEEP_H +#define OPENVPN_APPLE_MACSLEEP_H + +#include +#include +#include + +#include +#include + +#include + +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 diff --git a/openvpn/apple/macver.hpp b/openvpn/apple/macver.hpp new file mode 100644 index 0000000..b3c128b --- /dev/null +++ b/openvpn/apple/macver.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_APPLE_MACVER_H +#define OPENVPN_APPLE_MACVER_H + +#include +#include + +#include +#include +#include + +#include +#include +#include + +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 diff --git a/openvpn/apple/reach.hpp b/openvpn/apple/reach.hpp new file mode 100644 index 0000000..8aaf136 --- /dev/null +++ b/openvpn/apple/reach.hpp @@ -0,0 +1,43 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_APPLECRYPTO_UTIL_REACH_H +#define OPENVPN_APPLECRYPTO_UTIL_REACH_H + +// An interface to various network reachability implementations, +// primarily for iOS. + +namespace openvpn { + struct ReachabilityInterface + { + enum Status { + NotReachable, + ReachableViaWiFi, + ReachableViaWWAN + }; + + virtual Status reachable() const = 0; + virtual bool reachableVia(const std::string& net_type) const = 0; + virtual std::string to_string() const = 0; + virtual ~ReachabilityInterface() {} + }; +} +#endif diff --git a/openvpn/apple/reachable.hpp b/openvpn/apple/reachable.hpp new file mode 100644 index 0000000..abf808a --- /dev/null +++ b/openvpn/apple/reachable.hpp @@ -0,0 +1,468 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . +// +// This code is derived from the Apple sample Reachability.m under +// the following license. +// +// Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple +// Inc. ("Apple") in consideration of your agreement to the following +// terms, and your use, installation, modification or redistribution of +// this Apple software constitutes acceptance of these terms. If you do +// not agree with these terms, please do not use, install, modify or +// redistribute this Apple software. +// +// In consideration of your agreement to abide by the following terms, and +// subject to these terms, Apple grants you a personal, non-exclusive +// license, under Apple's copyrights in this original Apple software (the +// "Apple Software"), to use, reproduce, modify and redistribute the Apple +// Software, with or without modifications, in source and/or binary forms; +// provided that if you redistribute the Apple Software in its entirety and +// without modifications, you must retain this notice and the following +// text and disclaimers in all such redistributions of the Apple Software. +// Neither the name, trademarks, service marks or logos of Apple Inc. may +// be used to endorse or promote products derived from the Apple Software +// without specific prior written permission from Apple. Except as +// expressly stated in this notice, no other rights or licenses, express or +// implied, are granted by Apple herein, including but not limited to any +// patent rights that may be infringed by your derivative works or by other +// works in which the Apple Software may be incorporated. +// +// The Apple Software is provided by Apple on an "AS IS" basis. APPLE +// MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION +// THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND +// OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. +// +// IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL +// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, +// MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED +// AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), +// STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +// Copyright (C) 2013 Apple Inc. All Rights Reserved. + +// Wrapper for Apple SCNetworkReachability methods. + +#ifndef OPENVPN_APPLECRYPTO_UTIL_REACHABLE_H +#define OPENVPN_APPLECRYPTO_UTIL_REACHABLE_H + +#import "TargetConditionals.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace openvpn { + namespace CF { + OPENVPN_CF_WRAP(NetworkReachability, network_reachability_cast, SCNetworkReachabilityRef, SCNetworkReachabilityGetTypeID); + } + + class ReachabilityBase + { + public: + typedef ReachabilityInterface::Status Status; + + enum Type { + Internet, + WiFi, + }; + + std::string to_string() const + { + return to_string(flags()); + } + + std::string to_string(const SCNetworkReachabilityFlags f) const + { + const Status s = vstatus(f); + const Type t = vtype(); + + std::string ret; + ret += render_type(t); + ret += ':'; + ret += render_status(s); + ret += '/'; + ret += render_flags(f); + return ret; + } + + Status status() const + { + return vstatus(flags()); + } + + SCNetworkReachabilityFlags flags() const + { + SCNetworkReachabilityFlags f = 0; + if (SCNetworkReachabilityGetFlags(reach(), &f) == TRUE) + return f; + else + return 0; + } + + static std::string render_type(Type type) + { + switch (type) { + case Internet: + return "Internet"; + case WiFi: + return "WiFi"; + default: + return "Type???"; + } + } + + static std::string render_status(const Status status) + { + switch (status) { + case ReachabilityInterface::NotReachable: + return "NotReachable"; + case ReachabilityInterface::ReachableViaWiFi: + return "ReachableViaWiFi"; + case ReachabilityInterface::ReachableViaWWAN: + return "ReachableViaWWAN"; + default: + return "ReachableVia???"; + } + } + + static std::string render_flags(const SCNetworkReachabilityFlags flags) + { + std::string ret; +#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR // Mac OS X doesn't define WWAN flags + if (flags & kSCNetworkReachabilityFlagsIsWWAN) + ret += 'W'; + else +#endif + ret += '-'; + if (flags & kSCNetworkReachabilityFlagsReachable) + ret += 'R'; + else + ret += '-'; + ret += ' '; + if (flags & kSCNetworkReachabilityFlagsTransientConnection) + ret += 't'; + else + ret += '-'; + if (flags & kSCNetworkReachabilityFlagsConnectionRequired) + ret += 'c'; + else + ret += '-'; + if (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) + ret += 'C'; + else + ret += '-'; + if (flags & kSCNetworkReachabilityFlagsInterventionRequired) + ret += 'i'; + else + ret += '-'; + if (flags & kSCNetworkReachabilityFlagsConnectionOnDemand) + ret += 'D'; + else + ret += '-'; + if (flags & kSCNetworkReachabilityFlagsIsLocalAddress) + ret += 'l'; + else + ret += '-'; + if (flags & kSCNetworkReachabilityFlagsIsDirect) + ret += 'd'; + else + ret += '-'; + return ret; + } + + virtual Type vtype() const = 0; + virtual Status vstatus(const SCNetworkReachabilityFlags flags) const = 0; + + virtual ~ReachabilityBase() {} + + CF::NetworkReachability reach; + }; + + class ReachabilityViaInternet : public ReachabilityBase + { + public: + ReachabilityViaInternet() + { + struct sockaddr_in addr; + bzero(&addr, sizeof(addr)); + addr.sin_len = sizeof(addr); + addr.sin_family = AF_INET; + reach.reset(SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (struct sockaddr*)&addr)); + } + + virtual Type vtype() const + { + return Internet; + } + + virtual Status vstatus(const SCNetworkReachabilityFlags flags) const + { + return status_from_flags(flags); + } + + static Status status_from_flags(const SCNetworkReachabilityFlags flags) + { + if ((flags & kSCNetworkReachabilityFlagsReachable) == 0) + { + // The target host is not reachable. + return ReachabilityInterface::NotReachable; + } + + Status ret = ReachabilityInterface::NotReachable; + + if ((flags & kSCNetworkReachabilityFlagsConnectionRequired) == 0) + { + // If the target host is reachable and no connection is required then + // we'll assume (for now) that you're on Wi-Fi... + ret = ReachabilityInterface::ReachableViaWiFi; + } + +#if 0 // don't contaminate result by considering on-demand viability + if ((((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || + (flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)) + { + // ... and the connection is on-demand (or on-traffic) if the + // calling application is using the CFSocketStream or higher APIs... + + if ((flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0) + { + // ... and no [user] intervention is needed... + ret = ReachabilityInterface::ReachableViaWiFi; + } + } +#endif + +#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR // Mac OS X doesn't define WWAN flags + if ((flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN) + { + // ... but WWAN connections are OK if the calling application + // is using the CFNetwork APIs. + ret = ReachabilityInterface::ReachableViaWWAN; + } +#endif + + return ret; + } + }; + + class ReachabilityViaWiFi : public ReachabilityBase + { + public: + ReachabilityViaWiFi() + { + struct sockaddr_in addr; + bzero(&addr, sizeof(addr)); + addr.sin_len = sizeof(addr); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = htonl(IN_LINKLOCALNETNUM); // 169.254.0.0. + reach.reset(SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (struct sockaddr*)&addr)); + } + + virtual Type vtype() const + { + return WiFi; + } + + virtual Status vstatus(const SCNetworkReachabilityFlags flags) const + { + return status_from_flags(flags); + } + + static Status status_from_flags(const SCNetworkReachabilityFlags flags) + { + Status ret = ReachabilityInterface::NotReachable; + if ((flags & kSCNetworkReachabilityFlagsReachable) && (flags & kSCNetworkReachabilityFlagsIsDirect)) + ret = ReachabilityInterface::ReachableViaWiFi; + return ret; + } + }; + + class Reachability : public ReachabilityInterface + { + public: + Reachability(const bool enable_internet, const bool enable_wifi) + { + if (enable_internet) + internet.reset(new ReachabilityViaInternet); + if (enable_wifi) + wifi.reset(new ReachabilityViaWiFi); + } + + bool reachableViaWiFi() const { + if (internet) + { + if (wifi) + return internet->status() == ReachableViaWiFi && wifi->status() == ReachableViaWiFi; + else + return internet->status() == ReachableViaWiFi; + } + else + { + if (wifi) + return wifi->status() == ReachableViaWiFi; + else + return false; + } + } + + bool reachableViaCellular() const + { + if (internet) + return internet->status() == ReachableViaWWAN; + else + return false; + } + + virtual Status reachable() const + { + if (reachableViaWiFi()) + return ReachableViaWiFi; + else if (reachableViaCellular()) + return ReachableViaWWAN; + else + return NotReachable; + } + + virtual bool reachableVia(const std::string& net_type) const + { + if (net_type == "cellular") + return reachableViaCellular(); + else if (net_type == "wifi") + return reachableViaWiFi(); + else + return reachableViaWiFi() || reachableViaCellular(); + } + + virtual std::string to_string() const + { + std::string ret; + if (internet) + ret += internet->to_string(); + if (internet && wifi) + ret += ' '; + if (wifi) + ret += wifi->to_string(); + return ret; + } + + std::unique_ptr internet; + std::unique_ptr wifi; + }; + + class ReachabilityTracker + { + public: + ReachabilityTracker(const bool enable_internet, const bool enable_wifi) + : reachability(enable_internet, enable_wifi), + scheduled(false) + { + } + + void reachability_tracker_schedule() + { + if (!scheduled) + { + if (reachability.internet) + schedule(*reachability.internet, internet_callback_static); + if (reachability.wifi) + schedule(*reachability.wifi, wifi_callback_static); + scheduled = true; + } + } + + void reachability_tracker_cancel() + { + if (scheduled) + { + if (reachability.internet) + cancel(*reachability.internet); + if (reachability.wifi) + cancel(*reachability.wifi); + scheduled = false; + } + } + + virtual void reachability_tracker_event(const ReachabilityBase& rb, SCNetworkReachabilityFlags flags) = 0; + + virtual ~ReachabilityTracker() + { + reachability_tracker_cancel(); + } + + private: + bool schedule(ReachabilityBase& rb, SCNetworkReachabilityCallBack cb) + { + SCNetworkReachabilityContext context = { 0, this, nullptr, nullptr, nullptr }; + if (rb.reach.defined()) + { + if (SCNetworkReachabilitySetCallback(rb.reach(), + cb, + &context) == FALSE) + return false; + if (SCNetworkReachabilityScheduleWithRunLoop(rb.reach(), + CFRunLoopGetCurrent(), + kCFRunLoopCommonModes) == FALSE) + return false; + return true; + } + else + return false; + } + + void cancel(ReachabilityBase& rb) + { + if (rb.reach.defined()) + SCNetworkReachabilityUnscheduleFromRunLoop(rb.reach(), CFRunLoopGetCurrent(), kCFRunLoopCommonModes); + } + + static void internet_callback_static(SCNetworkReachabilityRef target, + SCNetworkReachabilityFlags flags, + void *info) + { + ReachabilityTracker* self = (ReachabilityTracker*)info; + self->reachability_tracker_event(*self->reachability.internet, flags); + } + + static void wifi_callback_static(SCNetworkReachabilityRef target, + SCNetworkReachabilityFlags flags, + void *info) + { + ReachabilityTracker* self = (ReachabilityTracker*)info; + self->reachability_tracker_event(*self->reachability.wifi, flags); + } + + Reachability reachability; + bool scheduled; + }; +} + +#endif diff --git a/openvpn/apple/scdynstore.hpp b/openvpn/apple/scdynstore.hpp new file mode 100644 index 0000000..647c9fc --- /dev/null +++ b/openvpn/apple/scdynstore.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_APPLE_SCDYNSTORE_H +#define OPENVPN_APPLE_SCDYNSTORE_H + +#include + +#include + +namespace openvpn { + namespace CF { + OPENVPN_CF_WRAP(DynamicStore, dynamic_store_cast, SCDynamicStoreRef, SCDynamicStoreGetTypeID) + + template + inline RET DynamicStoreCopy(const DynamicStore& ds, const KEY& key) + { + String keystr = string(key); + return RET(RET::cast(SCDynamicStoreCopyValue(ds(), keystr()))); + } + + template + inline Dict DynamicStoreCopyDict(const DynamicStore& ds, const KEY& key) + { + Dict dict = DynamicStoreCopy(ds, key); + if (dict.defined()) + return dict; + else + return CF::empty_dict(); + } + } +} + +#endif diff --git a/openvpn/apple/ver.hpp b/openvpn/apple/ver.hpp new file mode 100644 index 0000000..2e716da --- /dev/null +++ b/openvpn/apple/ver.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_APPLE_VER_H +#define OPENVPN_APPLE_VER_H + +#include +#include + +#include +#include +#include + +#include +#include + +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 StringList; + reset(); + StringList sl; + sl.reserve(3); + Split::by_char_void(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 diff --git a/openvpn/applecrypto/crypto/api.hpp b/openvpn/applecrypto/crypto/api.hpp new file mode 100644 index 0000000..d8147b1 --- /dev/null +++ b/openvpn/applecrypto/crypto/api.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_APPLECRYPTO_CRYPTO_API_H +#define OPENVPN_APPLECRYPTO_CRYPTO_API_H + +#include +#include +#include +#include + +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 diff --git a/openvpn/applecrypto/crypto/cipher.hpp b/openvpn/applecrypto/crypto/cipher.hpp new file mode 100644 index 0000000..bc686ed --- /dev/null +++ b/openvpn/applecrypto/crypto/cipher.hpp @@ -0,0 +1,201 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +// Wrap the Apple cipher API defined in 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 +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +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: + case CryptoAlgs::AES_256_CTR: + 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 diff --git a/openvpn/applecrypto/crypto/digest.hpp b/openvpn/applecrypto/crypto/digest.hpp new file mode 100644 index 0000000..79b7149 --- /dev/null +++ b/openvpn/applecrypto/crypto/digest.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +// Wrap the Apple digest API defined in +// 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 + +#include +#include + +#include +#include +#include +#include +#include + +#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 diff --git a/openvpn/applecrypto/crypto/hmac.hpp b/openvpn/applecrypto/crypto/hmac.hpp new file mode 100644 index 0000000..f53b5f0 --- /dev/null +++ b/openvpn/applecrypto/crypto/hmac.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_APPLECRYPTO_CRYPTO_HMAC_H +#define OPENVPN_APPLECRYPTO_CRYPTO_HMAC_H + +// Wrap the Apple HMAC API defined in so that +// it can be used as part of the crypto layer of the OpenVPN core. + +#include +#include + +#include + +#include +#include +#include + +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 diff --git a/openvpn/applecrypto/ssl/sslctx.hpp b/openvpn/applecrypto/ssl/sslctx.hpp new file mode 100644 index 0000000..699fb0b --- /dev/null +++ b/openvpn/applecrypto/ssl/sslctx.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +// Wrap the Apple SSL API as defined in +// 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 + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// 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 Ptr; + + enum { + MAX_CIPHERTEXT_IN = 64 + }; + + // The data needed to construct an AppleSSLContext. + class Config : public SSLConfigAPI + { + friend class AppleSSLContext; + + public: + typedef RCPtr 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 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 diff --git a/openvpn/applecrypto/util/rand.hpp b/openvpn/applecrypto/util/rand.hpp new file mode 100644 index 0000000..e026897 --- /dev/null +++ b/openvpn/applecrypto/util/rand.hpp @@ -0,0 +1,78 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +// Wrap the Apple Cryptographic Random API defined in +// so that it can be used as the primary source of cryptographic entropy by +// the OpenVPN core. + +#ifndef OPENVPN_APPLECRYPTO_UTIL_RAND_H +#define OPENVPN_APPLECRYPTO_UTIL_RAND_H + +#include + +#include + +namespace openvpn { + class AppleRandom : public RandomAPI + { + public: + OPENVPN_EXCEPTION(rand_error_apple); + + typedef RCPtr Ptr; + + AppleRandom(const bool prng) + { + } + + virtual std::string name() const + { + return "AppleRandom"; + } + + // Return true if algorithm is crypto-strength + virtual bool is_crypto() const + { + return true; + } + + // Fill buffer with random bytes + virtual void rand_bytes(unsigned char *buf, size_t size) + { + if (!rndbytes(buf, size)) + throw rand_error_apple("rand_bytes"); + } + + // Like rand_bytes, but don't throw exception. + // Return true on successs, false on fail. + virtual bool rand_bytes_noexcept(unsigned char *buf, size_t size) + { + return rndbytes(buf, size); + } + + private: + bool rndbytes(unsigned char *buf, size_t size) + { + return SecRandomCopyBytes(kSecRandomDefault, size, buf) ? false : true; + } + }; +} + +#endif diff --git a/openvpn/asio/asioboundsock.hpp b/openvpn/asio/asioboundsock.hpp new file mode 100644 index 0000000..f116751 --- /dev/null +++ b/openvpn/asio/asioboundsock.hpp @@ -0,0 +1,99 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +// Asio TCP socket that can be configured so that open() method +// always prebinds the socket to a given local address. Useful +// for TCP clients. + +#ifndef OPENVPN_ASIO_ASIOBOUNDSOCK_H +#define OPENVPN_ASIO_ASIOBOUNDSOCK_H + +#include + +#include +#include +#include + +namespace openvpn { + namespace AsioBoundSocket { + + typedef openvpn_io::basic_stream_socket SocketBase; + + class Socket : public SocketBase + { + public: + explicit Socket(openvpn_io::io_context& io_context) + : SocketBase(io_context) + { + } + + // if port 0, kernel will dynamically allocate free port + void bind_local(const IP::Addr& addr, const unsigned short port=0) + { + bind_local_addr = addr; + bind_local_port = port; + } + + std::string to_string() const + { + std::string ret; + ret.reserve(64); + if (bind_local_addr.defined()) + { + ret += "local=["; + ret += bind_local_addr.to_string(); + ret += "]:"; + ret += openvpn::to_string(bind_local_port); + } + try { + const std::string re = openvpn::to_string(remote_endpoint()); + if (!ret.empty()) + ret += ' '; + ret += "remote="; + ret += re; + } + catch (const std::exception& e) + { + } + return ret; + } + + protected: + virtual void async_connect_post_open(const protocol_type& protocol, openvpn_io::error_code& ec) override + { + if (bind_local_addr.defined()) + { + set_option(openvpn_io::socket_base::reuse_address(true), ec); + if (ec) + return; + bind(openvpn_io::ip::tcp::endpoint(bind_local_addr.to_asio(), bind_local_port), ec); + } + } + + private: + IP::Addr bind_local_addr; + unsigned short bind_local_port = 0; + }; + + } +} + +#endif diff --git a/openvpn/asio/asiocontext.hpp b/openvpn/asio/asiocontext.hpp new file mode 100644 index 0000000..c685ac6 --- /dev/null +++ b/openvpn/asio/asiocontext.hpp @@ -0,0 +1,51 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_ASIO_ASIOCONTEXT_H +#define OPENVPN_ASIO_ASIOCONTEXT_H + +#include +#include +#include + +#include + +namespace openvpn { + class AsioContextStore + { + public: + openvpn_io::io_context& new_context(int concurrency_hint) + { + openvpn_io::io_context* ioc = new openvpn_io::io_context(concurrency_hint); + { + std::lock_guard lock(mutex); + contexts.emplace_back(ioc); + } + return *ioc; + } + + private: + std::mutex mutex; + std::vector> contexts; + }; +} + +#endif diff --git a/openvpn/asio/asioerr.hpp b/openvpn/asio/asioerr.hpp new file mode 100644 index 0000000..d0204a4 --- /dev/null +++ b/openvpn/asio/asioerr.hpp @@ -0,0 +1,41 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_ASIO_ASIOERR_H +#define OPENVPN_ASIO_ASIOERR_H + +#include + +#include // was: #include + +namespace openvpn { + + // returns a string describing an i/o error code + template + inline std::string errinfo(ErrorCode err) + { + openvpn_io::error_code e(err, openvpn_io::system_category()); + return e.message(); + } + +} + +#endif diff --git a/openvpn/asio/asiopolysock.hpp b/openvpn/asio/asiopolysock.hpp new file mode 100644 index 0000000..d81e309 --- /dev/null +++ b/openvpn/asio/asiopolysock.hpp @@ -0,0 +1,377 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +// Asio polymorphic socket for handling TCP +// and unix domain sockets. + +#ifndef OPENVPN_ASIO_ASIOPOLYSOCK_H +#define OPENVPN_ASIO_ASIOPOLYSOCK_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING) +#include +#elif defined(OPENVPN_POLYSOCK_SUPPORTS_BIND) +#include +#endif + +#ifdef ASIO_HAS_LOCAL_SOCKETS +#include +#endif + +namespace openvpn { + namespace AsioPolySock { + // for shutdown() + enum ShutdownFlags { + SHUTDOWN_SEND = (1<<0), + SHUTDOWN_RECV = (1<<1), + }; + + class Base : public RC + { + public: + typedef RCPtr Ptr; + + virtual void async_send(const openvpn_io::const_buffer& buf, + Function&& callback) = 0; + + virtual void async_receive(const openvpn_io::mutable_buffer& buf, + Function&& callback) = 0; + + virtual std::string remote_endpoint_str() const = 0; + virtual bool remote_ip_port(IP::Addr& addr, unsigned int& port) const = 0; + + virtual void non_blocking(const bool state) = 0; + + virtual void close() = 0; + + virtual void shutdown(const unsigned int flags) {} + + virtual void tcp_nodelay() {} + virtual void set_cloexec() {} + + virtual int native_handle() + { + return -1; + } + +#ifdef ASIO_HAS_LOCAL_SOCKETS + virtual bool peercreds(SockOpt::Creds& cr) + { + return false; + } +#endif + +#if defined(OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING) + virtual bool alt_routing_enabled() + { + return false; + } +#endif + + virtual bool is_open() const = 0; + virtual bool is_local() const = 0; + + size_t index() const { return index_; } + + protected: + Base(const size_t index) + : index_(index) + { + } + + private: + size_t index_; + }; + + struct TCP : public Base + { + typedef RCPtr Ptr; + + TCP(openvpn_io::io_context& io_context, + const size_t index) + : Base(index), + socket(io_context) + { + } + + virtual void async_send(const openvpn_io::const_buffer& buf, + Function&& callback) override + { + socket.async_send(buf, std::move(callback)); + } + + virtual void async_receive(const openvpn_io::mutable_buffer& buf, + Function&& callback) override + { + socket.async_receive(buf, std::move(callback)); + } + +#if !defined(OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING) + virtual std::string remote_endpoint_str() const override + { + try { + return "TCP " + openvpn::to_string(socket.remote_endpoint()); + } + catch (const std::exception&) + { + return "TCP"; + } + } +#endif + + virtual bool remote_ip_port(IP::Addr& addr, unsigned int& port) const override + { + try { + addr = IP::Addr::from_asio(socket.remote_endpoint().address()); + port = socket.remote_endpoint().port(); + return true; + } + catch (const std::exception&) + { + return false; + } + } + + virtual void non_blocking(const bool state) override + { + socket.non_blocking(state); + } + + virtual void tcp_nodelay() override + { + socket.set_option(openvpn_io::ip::tcp::no_delay(true)); + } + +#if !defined(OPENVPN_PLATFORM_WIN) + virtual void set_cloexec() override + { + const int fd = socket.native_handle(); + if (fd >= 0) + SockOpt::set_cloexec(fd); + } +#endif + + virtual void shutdown(const unsigned int flags) override + { + if (flags & SHUTDOWN_SEND) + socket.shutdown(openvpn_io::ip::tcp::socket::shutdown_send); + else if (flags & SHUTDOWN_RECV) + socket.shutdown(openvpn_io::ip::tcp::socket::shutdown_receive); + } + + virtual void close() override + { + socket.close(); + } + + virtual bool is_open() const override + { + return socket.is_open(); + } + + virtual bool is_local() const override + { + return false; + } + + virtual int native_handle() override + { + return socket.native_handle(); + } + +#if defined(OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING) + virtual std::string remote_endpoint_str() const override + { + const char *proto = (socket.alt_routing_enabled() ? "TCP ALT " : "TCP "); + return proto + socket.to_string(); + } + + virtual bool alt_routing_enabled() override + { + return socket.alt_routing_enabled(); + } + + AltRouting::Socket socket; +#elif defined(OPENVPN_POLYSOCK_SUPPORTS_BIND) + AsioBoundSocket::Socket socket; +#else + openvpn_io::ip::tcp::socket socket; +#endif + }; + +#ifdef ASIO_HAS_LOCAL_SOCKETS + struct Unix : public Base + { + typedef RCPtr Ptr; + + Unix(openvpn_io::io_context& io_context, + const size_t index) + : Base(index), + socket(io_context) + { + } + + virtual void async_send(const openvpn_io::const_buffer& buf, + Function&& callback) override + { + socket.async_send(buf, std::move(callback)); + } + + virtual void async_receive(const openvpn_io::mutable_buffer& buf, + Function&& callback) override + { + socket.async_receive(buf, std::move(callback)); + } + + virtual std::string remote_endpoint_str() const override + { + return "LOCAL"; + } + + virtual bool remote_ip_port(IP::Addr&, unsigned int&) const override + { + return false; + } + + virtual void non_blocking(const bool state) override + { + socket.non_blocking(state); + } + + virtual bool peercreds(SockOpt::Creds& cr) override + { + return SockOpt::peercreds(socket.native_handle(), cr); + } + + virtual void set_cloexec() override + { + const int fd = socket.native_handle(); + if (fd >= 0) + SockOpt::set_cloexec(fd); + } + +#if !defined(OPENVPN_PLATFORM_MAC) + // shutdown() throws "socket is not connected" exception + // on macos if another side has called close() - this behavior + // breaks communication with agent, and hence disabled + virtual void shutdown(const unsigned int flags) override + { + if (flags & SHUTDOWN_SEND) + socket.shutdown(openvpn_io::ip::tcp::socket::shutdown_send); + else if (flags & SHUTDOWN_RECV) + socket.shutdown(openvpn_io::ip::tcp::socket::shutdown_receive); + } +#endif + + virtual void close() override + { + socket.close(); + } + + virtual bool is_open() const override + { + return socket.is_open(); + } + + virtual bool is_local() const override + { + return true; + } + + virtual int native_handle() override + { + return socket.native_handle(); + } + + openvpn_io::local::stream_protocol::socket socket; + }; +#endif + +#if defined(OPENVPN_PLATFORM_WIN) + struct NamedPipe : public Base + { + typedef RCPtr Ptr; + + NamedPipe(openvpn_io::windows::stream_handle&& handle_arg, + const size_t index) + : Base(index), + handle(std::move(handle_arg)) + { + } + + virtual void async_send(const openvpn_io::const_buffer& buf, + Function&& callback) override + { + handle.async_write_some(buf, std::move(callback)); + } + + virtual void async_receive(const openvpn_io::mutable_buffer& buf, + Function&& callback) override + { + handle.async_read_some(buf, std::move(callback)); + } + + virtual std::string remote_endpoint_str() const override + { + return "NAMED_PIPE"; + } + + virtual bool remote_ip_port(IP::Addr&, unsigned int&) const override + { + return false; + } + + virtual void non_blocking(const bool state) override + { + } + + virtual void close() override + { + handle.close(); + } + + virtual bool is_open() const override + { + return handle.is_open(); + } + + virtual bool is_local() const override + { + return true; + } + + openvpn_io::windows::stream_handle handle; + }; +#endif + } +} + +#endif diff --git a/openvpn/asio/asioresolverres.hpp b/openvpn/asio/asioresolverres.hpp new file mode 100644 index 0000000..627f1cf --- /dev/null +++ b/openvpn/asio/asioresolverres.hpp @@ -0,0 +1,49 @@ +// 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 . + +#pragma once + +#include + +#include + +namespace openvpn { + + template + inline std::string asio_resolver_results_to_string(const EPRANGE& endpoint_range) + { + std::string ret; + ret.reserve(64); + bool first = true; + for (const auto &i : endpoint_range) + { + if (!first) + ret += ' '; + ret += '['; + ret += openvpn::to_string(i.endpoint().address()); + ret += "]:"; + ret += openvpn::to_string(i.endpoint().port()); + first = false; + } + return ret; + } + +} diff --git a/openvpn/asio/asiosignal.hpp b/openvpn/asio/asiosignal.hpp new file mode 100644 index 0000000..022c0b9 --- /dev/null +++ b/openvpn/asio/asiosignal.hpp @@ -0,0 +1,104 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +// A simple class that allows an arbitrary set of posix signals to be +// associated with an Asio handler. + +#ifndef OPENVPN_ASIO_ASIOSIGNAL_H +#define OPENVPN_ASIO_ASIOSIGNAL_H + +#include + +#include +#include + +namespace openvpn { + + class ASIOSignals : public RC + { + public: + typedef RCPtr Ptr; + + ASIOSignals(openvpn_io::io_context& io_context) + : halt(false), signals_(io_context) {} + + enum { + S_SIGINT = (1<<0), + S_SIGTERM = (1<<1), +#ifndef OPENVPN_PLATFORM_WIN + S_SIGQUIT = (1<<2), + S_SIGHUP = (1<<3), + S_SIGUSR1 = (1<<4), + S_SIGUSR2 = (1<<5), +#endif + }; + + template + void register_signals(SignalHandler stop_handler, unsigned int sigmask = (S_SIGINT|S_SIGTERM)) + { + if (sigmask & S_SIGINT) + signals_.add(SIGINT); + if (sigmask & S_SIGTERM) + signals_.add(SIGTERM); +#ifndef OPENVPN_PLATFORM_WIN + if (sigmask & S_SIGQUIT) + signals_.add(SIGQUIT); + if (sigmask & S_SIGHUP) + signals_.add(SIGHUP); + if (sigmask & S_SIGUSR1) + signals_.add(SIGUSR1); + if (sigmask & S_SIGUSR2) + signals_.add(SIGUSR2); +#endif + signals_.async_wait(stop_handler); + } + + template + void register_signals_all(SignalHandler stop_handler) + { + register_signals(stop_handler, + S_SIGINT + | S_SIGTERM +#ifndef OPENVPN_PLATFORM_WIN + | S_SIGHUP + | S_SIGUSR1 + | S_SIGUSR2 +#endif + ); + } + + void cancel() + { + if (!halt) + { + halt = true; + signals_.cancel(); + } + } + + private: + bool halt; + openvpn_io::signal_set signals_; + }; + +} + +#endif diff --git a/openvpn/asio/asiostop.hpp b/openvpn/asio/asiostop.hpp new file mode 100644 index 0000000..b251841 --- /dev/null +++ b/openvpn/asio/asiostop.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_ASIO_ASIOSTOP_H +#define OPENVPN_ASIO_ASIOSTOP_H + +#include + +#include + +namespace openvpn { + class AsioStopScope : public Stop::Scope + { + public: + AsioStopScope(openvpn_io::io_context& io_context, + Stop* stop, + std::function&& method) + : Stop::Scope(stop, post_method(io_context, std::move(method))) + { + } + + private: + static std::function post_method(openvpn_io::io_context& io_context, std::function&& method) + { + return [&io_context, method=std::move(method)]() + { + openvpn_io::post(io_context, std::move(method)); + }; + } + }; + +} + +#endif diff --git a/openvpn/asio/asiowork.hpp b/openvpn/asio/asiowork.hpp new file mode 100644 index 0000000..a505b38 --- /dev/null +++ b/openvpn/asio/asiowork.hpp @@ -0,0 +1,44 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +// A null Asio unit of work, that prevents the Asio event loop from +// exiting. + +#ifndef OPENVPN_ASIO_ASIOWORK_H +#define OPENVPN_ASIO_ASIOWORK_H + +#include + +namespace openvpn { + class AsioWork + { + public: + AsioWork(openvpn_io::io_context& io_context) + : work(openvpn_io::make_work_guard(io_context)) + { + } + + private: + openvpn_io::executor_work_guard work; + }; +} + +#endif diff --git a/openvpn/asio/scoped_asio_stream.hpp b/openvpn/asio/scoped_asio_stream.hpp new file mode 100644 index 0000000..20f381a --- /dev/null +++ b/openvpn/asio/scoped_asio_stream.hpp @@ -0,0 +1,108 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +// A scoped Asio stream that is automatically closed by its destructor. + +#ifndef OPENVPN_ASIO_SCOPED_ASIO_STREAM_H +#define OPENVPN_ASIO_SCOPED_ASIO_STREAM_H + +#include + +namespace openvpn { + + template + class ScopedAsioStream + { + ScopedAsioStream(const ScopedAsioStream&) = delete; + ScopedAsioStream& operator=(const ScopedAsioStream&) = delete; + + public: + typedef STREAM* base_type; + + ScopedAsioStream() : obj_(undefined()) {} + + explicit ScopedAsioStream(STREAM *obj) + : obj_(obj) {} + + static STREAM* undefined() { return nullptr; } + + STREAM* release() + { + STREAM* ret = obj_; + obj_ = nullptr; + //OPENVPN_LOG("**** SAS RELEASE=" << ret); + return ret; + } + + static bool defined_static(STREAM* obj) + { + return obj != nullptr; + } + + bool defined() const + { + return defined_static(obj_); + } + + STREAM* operator()() const + { + return obj_; + } + + void reset(STREAM* obj) + { + close(); + obj_ = obj; + //OPENVPN_LOG("**** SAS RESET=" << obj_); + } + + // unusual semantics: replace obj without closing it first + void replace(STREAM* obj) + { + //OPENVPN_LOG("**** SAS REPLACE " << obj_ << " -> " << obj); + obj_ = obj; + } + + // return false if close error + bool close() + { + if (defined()) + { + //OPENVPN_LOG("**** SAS CLOSE obj=" << obj_); + delete obj_; + obj_ = nullptr; + } + return true; + } + + ~ScopedAsioStream() + { + //OPENVPN_LOG("**** SAS DESTRUCTOR"); + close(); + } + + private: + STREAM* obj_; + }; + +} // namespace openvpn + +#endif diff --git a/openvpn/auth/authcert.hpp b/openvpn/auth/authcert.hpp new file mode 100644 index 0000000..f22021a --- /dev/null +++ b/openvpn/auth/authcert.hpp @@ -0,0 +1,284 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_AUTH_AUTHCERT_H +#define OPENVPN_AUTH_AUTHCERT_H + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace openvpn { + + class OpenSSLContext; + class MbedTLSContext; + + class AuthCert : public RC + { + public: + // AuthCert needs to friend SSL implementation classes + friend class OpenSSLContext; + friend class MbedTLSContext; + + typedef RCPtr Ptr; + + class Fail + { + public: + // Ordered by severity. If many errors are present, the + // most severe error will be returned by get_code(). + enum Type { + OK=0, // OK MUST be 0 + EXPIRED, // less severe... + BAD_CERT_TYPE, + CERT_FAIL, + SNI_ERROR, // more severe... + N + }; + + void add_fail(const size_t depth, const Type new_code, std::string reason) + { + if (new_code > code) + code = new_code; + while (errors.size() <= depth) + errors.emplace_back(); + std::string& err = errors[depth]; + if (err.empty()) + err = std::move(reason); + else if (err.find(reason) == std::string::npos) + { + err += ", "; + err += reason; + } + } + + bool is_fail() const + { + return code != OK; + } + + Type get_code() const + { + return code; + } + + std::string to_string(const bool use_prefix) const + { + std::string ret; + if (use_prefix) + { + ret += render_code(code); + ret += ": "; + } + bool notfirst = false; + for (size_t i = 0; i < errors.size(); ++i) + { + if (errors[i].empty()) + continue; + if (notfirst) + ret += ", "; + notfirst = true; + ret += errors[i]; + ret += " ["; + ret += openvpn::to_string(i); + ret += ']'; + } + return ret; + } + + static std::string render_code(const Type code) + { + switch (code) + { + case OK: + return "OK"; + case CERT_FAIL: + default: + return "CERT_FAIL"; + case BAD_CERT_TYPE: + return "BAD_CERT_TYPE"; + case EXPIRED: + return "EXPIRED"; + case SNI_ERROR: + return "SNI_ERROR"; + } + } + + private: + Type code{OK}; // highest-valued cert fail code + std::vector errors; // human-readable cert errors by depth + }; + + AuthCert() + { + std::memset(issuer_fp, 0, sizeof(issuer_fp)); + sn = -1; + } + + bool defined() const + { + return sn >= 0; + } + + bool sni_defined() const + { + return !sni.empty(); + } + + bool cn_defined() const + { + return !cn.empty(); + } + + bool is_uninitialized() const + { + return cn.empty() && sn < 0 && !fail; + } + + template + T issuer_fp_prefix() const + { + return bin_prefix(issuer_fp); + } + + bool operator==(const AuthCert& other) const + { + return sni == other.sni && cn == other.cn && sn == other.sn && !std::memcmp(issuer_fp, other.issuer_fp, sizeof(issuer_fp)); + } + + bool operator!=(const AuthCert& other) const + { + return !operator==(other); + } + + std::string to_string() const + { + std::ostringstream os; + if (!sni.empty()) + os << "SNI=" << sni << ' '; + if (sni_metadata) + os << "SNI_CN=" << sni_metadata->sni_client_name(*this) << ' '; + os << "CN=" << cn + << " SN=" << sn + << " ISSUER_FP=" << issuer_fp_str(false); + return os.str(); + } + + std::string issuer_fp_str(const bool openssl_fmt) const + { + if (openssl_fmt) + return render_hex_sep(issuer_fp, sizeof(issuer_fp), ':', true); + else + return render_hex(issuer_fp, sizeof(issuer_fp), false); + } + + std::string normalize_cn() const // remove trailing "_AUTOLOGIN" from AS certs + { + if (string::ends_with(cn, "_AUTOLOGIN")) + return cn.substr(0, cn.length() - 10); + else + return cn; + } + + // Allow sni_metadata object, if it exists, to generate the client name. + // Otherwise fall back to normalize_cn(). + std::string sni_client_name() const + { + if (sni_metadata) + return sni_metadata->sni_client_name(*this); + else + return normalize_cn(); + } + + const std::string& get_sni() const + { + return sni; + } + + const std::string& get_cn() const + { + return cn; + } + + long get_sn() const + { + return sn; + } + + const X509Track::Set* x509_track_get() const + { + return x509_track.get(); + } + + std::unique_ptr x509_track_take_ownership() + { + return std::move(x509_track); + } + + void add_fail(const size_t depth, const Fail::Type new_code, std::string reason) + { + if (!fail) + fail.reset(new Fail()); + fail->add_fail(depth, new_code, std::move(reason)); + } + + bool is_fail() const + { + return fail && fail->is_fail(); + } + + const Fail* get_fail() const + { + return fail.get(); + } + + std::string fail_str() const + { + if (fail) + return fail->to_string(true); + else + return "OK"; + } + + private: + std::string sni; // SNI (server name indication) + std::string cn; // common name + long sn; // serial number + unsigned char issuer_fp[20]; // issuer cert fingerprint + + std::unique_ptr fail; + std::unique_ptr x509_track; + SNI::Metadata::UPtr sni_metadata; + }; +} + +#endif diff --git a/openvpn/auth/authcreds.hpp b/openvpn/auth/authcreds.hpp new file mode 100644 index 0000000..fcc3a4a --- /dev/null +++ b/openvpn/auth/authcreds.hpp @@ -0,0 +1,92 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_AUTH_AUTHCREDS +#define OPENVPN_AUTH_AUTHCREDS + +#include // for std::move +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace openvpn { + + class AuthCreds : public RC + { + public: + typedef RCPtr Ptr; + + AuthCreds(std::string&& username_arg, + SafeString&& password_arg, + const std::string& peer_info_str) + : username(std::move(username_arg)), + password(std::move(password_arg)) + { + peer_info.parse_from_peer_info(peer_info_str, nullptr); + peer_info.update_map(); + } + + bool defined() const + { + return !username.empty(); + } + + bool is_valid_user_pass(const bool strict) const + { + return ValidateCreds::is_valid(ValidateCreds::USERNAME, username, strict) + && ValidateCreds::is_valid(ValidateCreds::PASSWORD, password, strict); + } + + bool is_valid(const bool strict) const + { + return defined() && is_valid_user_pass(strict); + } + + void wipe_password() + { + password.wipe(); + } + + std::string to_string() const + { + std::ostringstream os; + os << "*** AuthCreds ***" << std::endl; + os << "user: '" << username << "'" << std::endl; + os << "pass: (" << password.length() << " chars)" << std::endl; + os << "peer info:" << std::endl; + os << peer_info.render(Option::RENDER_BRACKET|Option::RENDER_NUMBER); + return os.str(); + } + + std::string username; + SafeString password; + OptionList peer_info; + }; + +} + +#endif diff --git a/openvpn/auth/cr.hpp b/openvpn/auth/cr.hpp new file mode 100644 index 0000000..f94bc7d --- /dev/null +++ b/openvpn/auth/cr.hpp @@ -0,0 +1,228 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +// Encapsulate the state of a static or dynamic authentication challenge. + +#ifndef OPENVPN_AUTH_CR_H +#define OPENVPN_AUTH_CR_H + +#include +#include +#include + +#include +#include +#include +#include +#include + +// Static Challenge response: +// SCRV1:: +// +// Dynamic Challenge: +// CRV1:::: +// FLAGS is a comma-separated list of options: +// E -- echo +// R -- response required +// +// Dynamic Challenge response: +// Username: [username decoded from username_base64] +// Password: CRV1:::: + +namespace openvpn { + class ChallengeResponse : public RC { + public: + typedef RCPtr Ptr; + + OPENVPN_SIMPLE_EXCEPTION(dynamic_challenge_parse_error); + OPENVPN_SIMPLE_EXCEPTION(static_challenge_parse_error); + + ChallengeResponse() + : echo(false), response_required(false) + { + } + + explicit ChallengeResponse(const std::string& cookie) + : echo(false), response_required(false) + { + init(cookie); + } + + ChallengeResponse(const std::string& cookie, const std::string& user) + : echo(false), response_required(false) + { + if (!is_dynamic(cookie) && cookie.find_first_of(':') == std::string::npos) + { + state_id = cookie; + username = user; + } + else + init(cookie); + } + + void init(const std::string& cookie) + { + typedef std::vector StringList; + StringList sl; + sl.reserve(5); + Split::by_char_void(sl, cookie, ':', 0, 4); + if (sl.size() != 5) + throw dynamic_challenge_parse_error(); + if (sl[0] != "CRV1") + throw dynamic_challenge_parse_error(); + + // parse options + { + StringList opt; + opt.reserve(2); + Split::by_char_void(opt, sl[1], ','); + for (StringList::const_iterator i = opt.begin(); i != opt.end(); ++i) + { + if (*i == "E") + echo = true; + else if (*i == "R") + response_required = true; + } + } + + // save state ID + state_id = sl[2]; + + // save username + try { + username = base64->decode(sl[3]); + } + catch (const Base64::base64_decode_error&) + { + throw dynamic_challenge_parse_error(); + } + + // save challenge + challenge_text = sl[4]; + } + + static bool is_dynamic(const std::string& s) + { + return string::starts_with(s, "CRV1:"); + } + + static bool is_static(const std::string& s) + { + return string::starts_with(s, "SCRV1:"); + } + + static void validate_dynamic(const std::string& cookie) + { + ChallengeResponse cr(cookie); + } + + std::string construct_dynamic_password(const std::string& response) const + { + std::ostringstream os; + os << "CRV1::" << state_id << "::" << response; + return os.str(); + } + + static std::string construct_static_password(const std::string& password, + const std::string& response) + { + std::ostringstream os; + os << "SCRV1:" << base64->encode(password) << ':' << base64->encode(response); + return os.str(); + } + + static void parse_static_cookie(const std::string& cookie, + std::string& password, + std::string& response) + { + typedef std::vector StringList; + StringList sl; + sl.reserve(3); + Split::by_char_void(sl, cookie, ':'); + if (sl.size() != 3) + throw static_challenge_parse_error(); + if (sl[0] != "SCRV1") + throw static_challenge_parse_error(); + + // get password + try { + password = base64->decode(sl[1]); + } + catch (const Base64::base64_decode_error&) + { + throw static_challenge_parse_error(); + } + + // get response + try { + response = base64->decode(sl[2]); + } + catch (const Base64::base64_decode_error&) + { + throw static_challenge_parse_error(); + } + } + + static std::string generate_dynamic_challenge(const std::string& session_token, + const std::string& username, + const std::string& challenge, + const bool echo, + const bool response_required) + { + std::ostringstream os; + bool comma = false; + os << "CRV1:"; + if (echo) + { + if (comma) + os << ","; + os << "E"; + comma = true; + } + if (response_required) + { + if (comma) + os << ","; + os << "R"; + comma = true; + } + os << ':' << session_token; + os << ':' << base64->encode(username); + os << ':' << challenge; + return os.str(); + } + + const std::string& get_state_id() const { return state_id; } + const std::string& get_username() const { return username; } + bool get_echo() const { return echo; } + bool get_response_required() const { return response_required; } + const std::string& get_challenge_text() const { return challenge_text; } + + private: + bool echo; + bool response_required; + std::string state_id; + std::string username; + std::string challenge_text; + }; +} + +#endif diff --git a/openvpn/auth/validatecreds.hpp b/openvpn/auth/validatecreds.hpp new file mode 100644 index 0000000..8a71afc --- /dev/null +++ b/openvpn/auth/validatecreds.hpp @@ -0,0 +1,71 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_AUTH_VALIDATE_CREDS_H +#define OPENVPN_AUTH_VALIDATE_CREDS_H + +#include + +namespace openvpn { + // Validate authentication credential. + // Must be UTF-8. + // Other checks on size and content below. + // We don't check that the credential is non-empty. + namespace ValidateCreds { + + enum Type { + USERNAME, + PASSWORD, + RESPONSE + }; + + template + static bool is_valid(const Type type, const STRING& cred, const bool strict) + { + size_t max_len_flags; + if (strict) + { + // length <= 512 unicode chars, no control chars allowed + max_len_flags = 512 | Unicode::UTF8_NO_CTRL; + } + else + { + switch (type) + { + case USERNAME: + // length <= 512 unicode chars, no control chars allowed + max_len_flags = 512 | Unicode::UTF8_NO_CTRL; + break; + case PASSWORD: + case RESPONSE: + // length <= 16384 unicode chars + max_len_flags = 16384; + break; + default: + return false; + } + } + return Unicode::is_valid_utf8(cred, max_len_flags); + } + } +} + +#endif diff --git a/openvpn/buffer/asiobuf.hpp b/openvpn/buffer/asiobuf.hpp new file mode 100644 index 0000000..10e199f --- /dev/null +++ b/openvpn/buffer/asiobuf.hpp @@ -0,0 +1,56 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_BUFFER_ASIOBUF_H +#define OPENVPN_BUFFER_ASIOBUF_H + +#include + +#include + +namespace openvpn { + class AsioConstBufferSeq2 + { + public: + AsioConstBufferSeq2(const Buffer& b1, const Buffer& b2) + : buf({{b1.c_data(), b1.size()}, + {b2.c_data(), b2.size()}}) + { + } + + // Implement the ConstBufferSequence requirements. + typedef openvpn_io::const_buffer value_type; + typedef const openvpn_io::const_buffer* const_iterator; + const openvpn_io::const_buffer* begin() const { return buf; } + const openvpn_io::const_buffer* end() const { return buf + 2; } + + const size_t size() const + { + return openvpn_io::buffer_size(buf[0]) + + openvpn_io::buffer_size(buf[1]); + } + + private: + const openvpn_io::const_buffer buf[2]; + }; +} + +#endif diff --git a/openvpn/buffer/bufclamp.hpp b/openvpn/buffer/bufclamp.hpp new file mode 100644 index 0000000..0965fbb --- /dev/null +++ b/openvpn/buffer/bufclamp.hpp @@ -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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +// For debugging, reduce effective buffer size for I/O. +// Enable by defining OPENVPN_BUF_CLAMP_READ and/or OPENVPN_BUF_CLAMP_WRITE + +#ifndef OPENVPN_BUFFER_BUFCLAMP_H +#define OPENVPN_BUFFER_BUFCLAMP_H + +#include + +#include + +namespace openvpn { + inline size_t buf_clamp_read(const size_t size) + { +#ifdef OPENVPN_BUF_CLAMP_READ + return std::min(size, size_t(OPENVPN_BUF_CLAMP_READ)); +#else + return size; +#endif + } + + inline size_t buf_clamp_write(const size_t size) + { +#ifdef OPENVPN_BUF_CLAMP_WRITE + return std::min(size, size_t(OPENVPN_BUF_CLAMP_WRITE)); +#else + return size; +#endif + } +} + +#endif diff --git a/openvpn/buffer/bufcomplete.hpp b/openvpn/buffer/bufcomplete.hpp new file mode 100644 index 0000000..b1df2e8 --- /dev/null +++ b/openvpn/buffer/bufcomplete.hpp @@ -0,0 +1,112 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_BUFFER_BUFCOMPLETE_H +#define OPENVPN_BUFFER_BUFCOMPLETE_H + +#include // for std::uint32_t, uint16_t, uint8_t +#include // for std::min + +#include + +namespace openvpn { + + class BufferComplete + { + public: + /* each advance/get method returns false if message is incomplete */ + + bool advance(size_t size) + { + while (size) + { + if (!fetch_buffer()) + return false; + const size_t s = std::min(size, buf.size()); + buf.advance(s); + size -= s; + } + return true; + } + + // assumes embedded big-endian uint16_t length in the stream + bool advance_string() + { + std::uint8_t h, l; + if (!get(h)) + return false; + if (!get(l)) + return false; + return advance(size_t(h) << 8 | size_t(l)); + } + + bool advance_to_null() + { + std::uint8_t c; + while (get(c)) + { + if (!c) + return true; + } + return false; + } + + bool get(std::uint8_t& c) + { + if (!fetch_buffer()) + return false; + c = buf.pop_front(); + return true; + } + + bool defined() const + { + return buf.defined(); + } + + protected: + void reset_buf(const Buffer& buf_arg) + { + buf = buf_arg; + } + + void reset_buf() + { + buf.reset_content(); + } + + private: + virtual void next_buffer() = 0; + + bool fetch_buffer() + { + if (buf.defined()) + return true; + next_buffer(); + return buf.defined(); + } + + Buffer buf; + }; + +} + +#endif diff --git a/openvpn/buffer/bufcomposed.hpp b/openvpn/buffer/bufcomposed.hpp new file mode 100644 index 0000000..fe93ab7 --- /dev/null +++ b/openvpn/buffer/bufcomposed.hpp @@ -0,0 +1,94 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_BUFFER_BUFCOMPOSED_H +#define OPENVPN_BUFFER_BUFCOMPOSED_H + +#include +#include +#include + +namespace openvpn { + class BufferComposed + { + public: + class Complete : public BufferComplete + { + public: + BufferPtr get() + { +#if 0 // don't include for production + if (iter_defined()) + throw Exception("BufferComposed::Complete: residual data"); +#endif + BufferPtr ret = bc.bv.join(); + bc.bv.clear(); + return ret; + } + + private: + friend class BufferComposed; + + Complete(BufferComposed& bc_arg) + : bc(bc_arg), + iter(bc.bv.cbegin()) + { + next_buffer(); + } + + bool iter_defined() + { + return iter != bc.bv.end(); + } + + virtual void next_buffer() override + { + if (iter_defined()) + reset_buf(**iter++); + else + reset_buf(); + } + + BufferComposed& bc; + BufferVector::const_iterator iter; + }; + + size_t size() const + { + return bv.join_size(); + } + + void put(BufferPtr bp) + { + bv.push_back(std::move(bp)); + } + + Complete complete() + { + return Complete(*this); + } + + private: + BufferVector bv; + }; +} + +#endif diff --git a/openvpn/buffer/buffer.hpp b/openvpn/buffer/buffer.hpp new file mode 100644 index 0000000..30c35b3 --- /dev/null +++ b/openvpn/buffer/buffer.hpp @@ -0,0 +1,911 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +// These templates define the fundamental data buffer classes used by the +// OpenVPN core. Normally OpenVPN uses buffers of unsigned chars, but the +// templatization of the classes would allow buffers of other types to +// be defined. +// +// Fundamentally a buffer is an object with 4 fields: +// +// 1. a pointer to underlying data array +// 2. the capacity of the underlying data array +// 3. an offset into the data array +// 4. the size of the referenced data within the array +// +// The BufferType template is the lowest-level buffer class template. It refers +// to a buffer but without any notion of ownership of the underlying data. +// +// The BufferAllocatedType template is a higher-level template that inherits +// from BufferType but which asserts ownership over the resources of the buffer -- +// for example, it will free the underlying buffer in its destructor. +// +// Since most of the time, we want our buffers to be made out of unsigned chars, +// some typedefs at the end of the file define common instantations for the +// BufferType and BufferAllocatedType templates. +// +// Buffer : a simple buffer of unsigned char without ownership semantics +// ConstBuffer : like buffer but where the data pointed to by the buffer is const +// BufferAllocated : an allocated Buffer with ownership semantics +// BufferPtr : a smart, reference-counted pointer to a BufferAllocated + +#ifndef OPENVPN_BUFFER_BUFFER_H +#define OPENVPN_BUFFER_BUFFER_H + +#include +#include +#include +#include // for std::is_nothrow_move_constructible, std::remove_const + +#ifndef OPENVPN_NO_IO +#include +#endif + +#include +#include +#include +#include +#include + +#ifdef OPENVPN_BUFFER_ABORT +#define OPENVPN_BUFFER_THROW(exc) { std::abort(); } +#else +#define OPENVPN_BUFFER_THROW(exc) { throw BufferException(BufferException::exc); } +#endif + +namespace openvpn { + + // special-purpose exception class for Buffer classes + class BufferException : public std::exception + { + public: + enum Status { + buffer_full, + buffer_headroom, + buffer_underflow, + buffer_overflow, + buffer_offset, + buffer_index, + buffer_const_index, + buffer_push_front_headroom, + buffer_no_reset_impl, + buffer_pop_back, + buffer_set_size, + buffer_range, + }; + + BufferException(Status status) + : status_(status) {} + + Status status() const { return status_; } + + const char *status_string() const + { + switch (status_) + { + case buffer_full: + return "buffer_full"; + case buffer_headroom: + return "buffer_headroom"; + case buffer_underflow: + return "buffer_underflow"; + case buffer_overflow: + return "buffer_overflow"; + case buffer_offset: + return "buffer_offset"; + case buffer_index: + return "buffer_index"; + case buffer_const_index: + return "buffer_const_index"; + case buffer_push_front_headroom: + return "buffer_push_front_headroom"; + case buffer_no_reset_impl: + return "buffer_no_reset_impl"; + case buffer_pop_back: + return "buffer_pop_back"; + case buffer_set_size: + return "buffer_set_size"; + case buffer_range: + return "buffer_range"; + default: + return "buffer_???"; + } + } + + virtual const char* what() const throw() { + return status_string(); + } + virtual ~BufferException() throw() {} + + private: + Status status_; + }; + + template + class BufferAllocatedType; + + template + class BufferType { + template friend class BufferAllocatedType; + + public: + typedef T value_type; + typedef T* type; + typedef const T* const_type; + typedef typename std::remove_const::type NCT; // non-const type + + BufferType() + { + static_assert(std::is_nothrow_move_constructible::value, "class BufferType not noexcept move constructable"); + data_ = nullptr; + offset_ = size_ = capacity_ = 0; + } + + BufferType(T* data, const size_t size, const bool filled) + { + data_ = data; + offset_ = 0; + capacity_ = size; + size_ = filled ? size : 0; + } + + void reserve(const size_t n) + { + if (n > capacity_) + resize(n); + } + + void init_headroom(const size_t headroom) + { + if (headroom > capacity_) + OPENVPN_BUFFER_THROW(buffer_headroom); + offset_ = headroom; + size_ = 0; + } + + void reset_offset(const size_t offset) + { + const size_t size = size_ + offset_ - offset; + if (offset > capacity_ || size > capacity_ || offset + size > capacity_) + OPENVPN_BUFFER_THROW(buffer_offset); + offset_ = offset; + size_ = size; + } + + void reset_size() + { + size_ = 0; + } + + void reset_content() + { + offset_ = size_ = 0; + } + + // std::string compatible methods + const T* c_str() const { return c_data(); } + size_t length() const { return size(); } + + // return a const pointer to start of array + const T* c_data() const { return data_ + offset_; } + + // return a mutable pointer to start of array + T* data() { return data_ + offset_; } + + // return a const pointer to end of array + const T* c_data_end() const { return data_ + offset_ + size_; } + + // return a mutable pointer to end of array + T* data_end() { return data_ + offset_ + size_; } + + // return a const pointer to start of raw data + const T* c_data_raw() const { return data_; } + + // return a mutable pointer to start of raw data + T* data_raw() { return data_; } + + // return size of array in T objects + size_t size() const { return size_; } + + // return raw size of allocated buffer in T objects + size_t capacity() const { return capacity_; } + + // return current offset (headroom) into buffer + size_t offset() const { return offset_; } + + // return true if array is not empty + bool defined() const { return size_ > 0; } + + // return true if data memory is defined + bool allocated() const { return data_ != nullptr; } + + // return true if array is empty + bool empty() const { return !size_; } + + // return the number of additional T objects that can be added before capacity is reached (without considering resize) + size_t remaining(const size_t tailroom = 0) const { + const size_t r = capacity_ - (offset_ + size_ + tailroom); + return r <= capacity_ ? r : 0; + } + + // return the maximum allowable size value in T objects given the current offset (without considering resize) + size_t max_size() const { + const size_t r = capacity_ - offset_; + return r <= capacity_ ? r : 0; + } + + // like max_size, but take tailroom into account + size_t max_size_tailroom(const size_t tailroom) const { + const size_t r = capacity_ - (offset_ + tailroom); + return r <= capacity_ ? r : 0; + } + + // After an external method, operating on the array as + // a mutable unsigned char buffer, has written data to the + // array, use this method to set the array length in terms + // of T objects. + void set_size(const size_t size) + { + if (size > max_size()) + OPENVPN_BUFFER_THROW(buffer_set_size); + size_ = size; + } + + // Increment size (usually used in a similar context + // to set_size such as after mutable_buffer_append). + void inc_size(const size_t delta) + { + set_size(size_ + delta); + } + + // append a T object to array, with possible resize + void push_back(const T& value) + { + if (!remaining()) + resize(offset_ + size_ + 1); + *(data()+size_++) = value; + } + + // append a T object to array, with possible resize + void push_front(const T& value) + { + if (!offset_) + OPENVPN_BUFFER_THROW(buffer_push_front_headroom); + --offset_; + ++size_; + *data() = value; + } + + T pop_back() + { + if (!size_) + OPENVPN_BUFFER_THROW(buffer_pop_back); + return *(data()+(--size_)); + } + + T pop_front() + { + T ret = (*this)[0]; + ++offset_; + --size_; + return ret; + } + + T front() + { + return (*this)[0]; + } + + T back() + { + return (*this)[size_-1]; + } + + // Place a T object after the last object in the + // array, with possible resize to contain it, + // however don't actually change the size of the + // array to reflect the added object. Useful + // for maintaining null-terminated strings. + void set_trailer(const T& value) + { + if (!remaining()) + resize(offset_ + size_ + 1); + *(data()+size_) = value; + } + + void null_terminate() + { + if (empty() || back()) + push_back(0); + } + + void advance(const size_t delta) + { + if (delta > size_) + OPENVPN_BUFFER_THROW(buffer_overflow); + offset_ += delta; + size_ -= delta; + } + + bool contains_null() const + { + const T* end = c_data_end(); + for (const T* p = c_data(); p < end; ++p) + { + if (!*p) + return true; + } + return false; + } + + bool is_zeroed() const + { + const T* end = c_data_end(); + for (const T* p = c_data(); p < end; ++p) + { + if (*p) + return false; + } + return true; + } + + // mutable index into array + T& operator[](const size_t index) + { + if (index >= size_) + OPENVPN_BUFFER_THROW(buffer_index); + return data()[index]; + } + + // const index into array + const T& operator[](const size_t index) const + { + if (index >= size_) + OPENVPN_BUFFER_THROW(buffer_const_index); + return c_data()[index]; + } + + // mutable index into array + T* index(const size_t index) + { + if (index >= size_) + OPENVPN_BUFFER_THROW(buffer_index); + return &data()[index]; + } + + // const index into array + const T* c_index(const size_t index) const + { + if (index >= size_) + OPENVPN_BUFFER_THROW(buffer_const_index); + return &c_data()[index]; + } + + bool operator==(const BufferType& other) const + { + if (size_ != other.size_) + return false; + return std::memcmp(c_data(), other.c_data(), size_) == 0; + } + + bool operator!=(const BufferType& other) const + { + return !(*this == other); + } + +#ifndef OPENVPN_NO_IO + // return a openvpn_io::mutable_buffer object used by + // asio read methods, starting from data() + openvpn_io::mutable_buffer mutable_buffer(const size_t tailroom = 0) + { + return openvpn_io::mutable_buffer(data(), max_size_tailroom(tailroom)); + } + + // return a openvpn_io::mutable_buffer object used by + // asio read methods, starting from data_end() + openvpn_io::mutable_buffer mutable_buffer_append(const size_t tailroom = 0) + { + return openvpn_io::mutable_buffer(data_end(), remaining(tailroom)); + } + + // return a openvpn_io::const_buffer object used by + // asio write methods. + openvpn_io::const_buffer const_buffer() const + { + return openvpn_io::const_buffer(c_data(), size()); + } + + // clamped versions of mutable_buffer(), mutable_buffer_append(), + // and const_buffer() + + openvpn_io::mutable_buffer mutable_buffer_clamp(const size_t tailroom = 0) + { + return openvpn_io::mutable_buffer(data(), buf_clamp_read(max_size_tailroom(tailroom))); + } + + openvpn_io::mutable_buffer mutable_buffer_append_clamp(const size_t tailroom = 0) + { + return openvpn_io::mutable_buffer(data_end(), buf_clamp_read(remaining(tailroom))); + } + + openvpn_io::const_buffer const_buffer_clamp() const + { + return openvpn_io::const_buffer(c_data(), buf_clamp_write(size())); + } + + openvpn_io::const_buffer const_buffer_limit(const size_t limit) const + { + return openvpn_io::const_buffer(c_data(), std::min(buf_clamp_write(size()), limit)); + } +#endif + + void realign(size_t headroom) + { + if (headroom != offset_) + { + if (headroom + size_ > capacity_) + OPENVPN_BUFFER_THROW(buffer_headroom); + std::memmove(data_ + headroom, data_ + offset_, size_); + offset_ = headroom; + } + } + + void write(const T* data, const size_t size) + { + std::memcpy(write_alloc(size), data, size * sizeof(T)); + } + + void write(const void* data, const size_t size) + { + write((const T*)data, size); + } + + void prepend(const T* data, const size_t size) + { + std::memcpy(prepend_alloc(size), data, size * sizeof(T)); + } + + void prepend(const void* data, const size_t size) + { + prepend((const T*)data, size); + } + + void read(NCT* data, const size_t size) + { + std::memcpy(data, read_alloc(size), size * sizeof(T)); + } + + void read(void* data, const size_t size) + { + read((NCT*)data, size); + } + + T* write_alloc(const size_t size) + { + if (size > remaining()) + resize(offset_ + size_ + size); + T* ret = data() + size_; + size_ += size; + return ret; + } + + T* prepend_alloc(const size_t size) + { + if (size <= offset_) + { + offset_ -= size; + size_ += size; + return data(); + } + else + OPENVPN_BUFFER_THROW(buffer_headroom); + } + + T* read_alloc(const size_t size) + { + if (size <= size_) + { + T* ret = data(); + offset_ += size; + size_ -= size; + return ret; + } + else + OPENVPN_BUFFER_THROW(buffer_underflow); + } + + BufferType read_alloc_buf(const size_t size) + { + if (size <= size_) + { + BufferType ret(data_, offset_, size, capacity_); + offset_ += size; + size_ -= size; + return ret; + } + else + OPENVPN_BUFFER_THROW(buffer_underflow); + } + + void reset(const size_t min_capacity, const unsigned int flags) + { + if (min_capacity > capacity_) + reset_impl(min_capacity, flags); + } + + void reset(const size_t headroom, const size_t min_capacity, const unsigned int flags) + { + reset(min_capacity, flags); + init_headroom(headroom); + } + + template + void append(const B& other) + { + write(other.c_data(), other.size()); + } + + BufferType range(size_t offset, size_t len) const + { + if (offset + len > size()) + { + if (offset < size()) + len = size() - offset; + else + len = 0; + } + return BufferType(datac(), offset, len, len); + } + + protected: + BufferType(T* data, const size_t offset, const size_t size, const size_t capacity) + : data_(data), offset_(offset), size_(size), capacity_(capacity) + { + } + + // return a mutable pointer to start of array but + // remain const with respect to *this. + T* datac() const { return data_ + offset_; } + + // Called when reset method needs to expand the buffer size + virtual void reset_impl(const size_t min_capacity, const unsigned int flags) + { + OPENVPN_BUFFER_THROW(buffer_no_reset_impl); + } + + // Derived classes can implement buffer growing semantics + // by overloading this method. In the default implementation, + // buffers are non-growable, so we throw an exception. + virtual void resize(const size_t new_capacity) + { + if (new_capacity > capacity_) + { + OPENVPN_BUFFER_THROW(buffer_full); + } + } + + T* data_; // pointer to data + size_t offset_; // offset from data_ of beginning of T array (to allow for headroom) + size_t size_; // number of T objects in array starting at data_ + offset_ + size_t capacity_; // maximum number of array objects of type T for which memory is allocated, starting at data_ + }; + + template + class BufferAllocatedType : public BufferType, public RC + { + using BufferType::data_; + using BufferType::offset_; + using BufferType::size_; + using BufferType::capacity_; + + template friend class BufferAllocatedType; + + public: + enum { + CONSTRUCT_ZERO = (1<<0), // if enabled, constructors/init will zero allocated space + DESTRUCT_ZERO = (1<<1), // if enabled, destructor will zero data before deletion + GROW = (1<<2), // if enabled, buffer will grow (otherwise buffer_full exception will be thrown) + ARRAY = (1<<3), // if enabled, use as array + }; + + BufferAllocatedType() + { + static_assert(std::is_nothrow_move_constructible::value, "class BufferAllocatedType not noexcept move constructable"); + flags_ = 0; + } + + BufferAllocatedType(const size_t capacity, const unsigned int flags) + { + flags_ = flags; + capacity_ = capacity; + if (capacity) + { + data_ = new T[capacity]; + if (flags & CONSTRUCT_ZERO) + std::memset(data_, 0, capacity * sizeof(T)); + if (flags & ARRAY) + size_ = capacity; + } + } + + BufferAllocatedType(const T* data, const size_t size, const unsigned int flags) + { + flags_ = flags; + size_ = capacity_ = size; + if (size) + { + data_ = new T[size]; + std::memcpy(data_, data, size * sizeof(T)); + } + } + + BufferAllocatedType(const BufferAllocatedType& other) + { + offset_ = other.offset_; + size_ = other.size_; + capacity_ = other.capacity_; + flags_ = other.flags_; + if (capacity_) + { + data_ = new T[capacity_]; + if (size_) + std::memcpy(data_ + offset_, other.data_ + offset_, size_ * sizeof(T)); + } + } + + template + BufferAllocatedType(const BufferType& other, const unsigned int flags) + { + static_assert(sizeof(T) == sizeof(T_), "size inconsistency"); + offset_ = other.offset_; + size_ = other.size_; + capacity_ = other.capacity_; + flags_ = flags; + if (capacity_) + { + data_ = new T[capacity_]; + if (size_) + std::memcpy(data_ + offset_, other.data_ + offset_, size_ * sizeof(T)); + } + } + + void operator=(const BufferAllocatedType& other) + { + if (this != &other) + { + offset_ = size_ = 0; + if (capacity_ != other.capacity_) + { + erase_(); + if (other.capacity_) + data_ = new T[other.capacity_]; + capacity_ = other.capacity_; + } + offset_ = other.offset_; + size_ = other.size_; + flags_ = other.flags_; + if (size_) + std::memcpy(data_ + offset_, other.data_ + offset_, size_ * sizeof(T)); + } + } + + void init(const size_t capacity, const unsigned int flags) + { + offset_ = size_ = 0; + flags_ = flags; + if (capacity_ != capacity) + { + erase_(); + if (capacity) + { + data_ = new T[capacity]; + } + capacity_ = capacity; + } + if ((flags & CONSTRUCT_ZERO) && capacity) + std::memset(data_, 0, capacity * sizeof(T)); + if (flags & ARRAY) + size_ = capacity; + } + + void init(const T* data, const size_t size, const unsigned int flags) + { + offset_ = size_ = 0; + flags_ = flags; + if (size != capacity_) + { + erase_(); + if (size) + data_ = new T[size]; + capacity_ = size; + } + size_ = size; + std::memcpy(data_, data, size * sizeof(T)); + } + + void realloc(const size_t newcap) + { + if (newcap > capacity_) + realloc_(newcap); + } + + void reset(const size_t min_capacity, const unsigned int flags) + { + if (min_capacity > capacity_) + init (min_capacity, flags); + } + + void reset(const size_t headroom, const size_t min_capacity, const unsigned int flags) + { + reset(min_capacity, flags); + BufferType::init_headroom(headroom); + } + + template + void move(BufferAllocatedType& other) + { + if (data_) + delete_(data_, capacity_, flags_); + move_(other); + } + + RCPtr> move_to_ptr() + { + RCPtr> bp = new BufferAllocatedType(); + bp->move(*this); + return bp; + } + + void swap(BufferAllocatedType& other) + { + std::swap(data_, other.data_); + std::swap(offset_, other.offset_); + std::swap(size_, other.size_); + std::swap(capacity_, other.capacity_); + std::swap(flags_, other.flags_); + } + + template + BufferAllocatedType(BufferAllocatedType&& other) noexcept + { + move_(other); + } + + BufferAllocatedType& operator=(BufferAllocatedType&& other) noexcept + { + move(other); + return *this; + } + + void clear() + { + erase_(); + flags_ = 0; + size_ = offset_ = 0; + } + + void or_flags(const unsigned int flags) + { + flags_ |= flags; + } + + void and_flags(const unsigned int flags) + { + flags_ &= flags; + } + + ~BufferAllocatedType() + { + if (data_) + delete_(data_, capacity_, flags_); + } + + protected: + // Called when reset method needs to expand the buffer size + virtual void reset_impl(const size_t min_capacity, const unsigned int flags) + { + init(min_capacity, flags); + } + + // Set current capacity to at least new_capacity. + virtual void resize(const size_t new_capacity) + { + const size_t newcap = std::max(new_capacity, capacity_ * 2); + if (newcap > capacity_) + { + if (flags_ & GROW) + realloc_(newcap); + else + OPENVPN_BUFFER_THROW(buffer_full); + } + } + + void realloc_(const size_t newcap) + { + T* data = new T[newcap]; + if (size_) + std::memcpy(data + offset_, data_ + offset_, size_ * sizeof(T)); + delete_(data_, capacity_, flags_); + data_ = data; + //std::cout << "*** RESIZE " << capacity_ << " -> " << newcap << std::endl; // fixme + capacity_ = newcap; + } + + template + void move_(BufferAllocatedType& other) + { + data_ = other.data_; + offset_ = other.offset_; + size_ = other.size_; + capacity_ = other.capacity_; + flags_ = other.flags_; + + other.data_ = nullptr; + other.offset_ = other.size_ = other.capacity_ = 0; + } + + void erase_() + { + if (data_) + { + delete_(data_, capacity_, flags_); + data_ = nullptr; + } + capacity_ = 0; + } + + static void delete_(T* data, const size_t size, const unsigned int flags) + { + if (size && (flags & DESTRUCT_ZERO)) + std::memset(data, 0, size * sizeof(T)); + delete [] data; + } + + unsigned int flags_; + }; + + // specializations of BufferType for unsigned char + typedef BufferType Buffer; + typedef BufferType ConstBuffer; + typedef BufferAllocatedType BufferAllocated; + typedef RCPtr BufferPtr; + + // BufferAllocated with thread-safe refcount + typedef BufferAllocatedType BufferAllocatedTS; + typedef RCPtr BufferPtrTS; + + // cast BufferType to BufferType + + template + inline BufferType& const_buffer_ref(BufferType& src) + { + return (BufferType&)src; + } + + template + inline const BufferType& const_buffer_ref(const BufferType& src) + { + return (const BufferType&)src; + } + +} // namespace openvpn + +#endif // OPENVPN_BUFFER_BUFFER_H diff --git a/openvpn/buffer/bufhex.hpp b/openvpn/buffer/bufhex.hpp new file mode 100644 index 0000000..9f1c60b --- /dev/null +++ b/openvpn/buffer/bufhex.hpp @@ -0,0 +1,61 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_BUFFER_BUFHEX_H +#define OPENVPN_BUFFER_BUFHEX_H + +#include +#include +#include + +namespace openvpn { + namespace BufHex { + + OPENVPN_EXCEPTION(buf_hex); + + template + inline std::string render(const T obj) + { + const ConstBuffer buf((const unsigned char *)&obj, sizeof(obj), true); + return render_hex_generic(buf); + } + + template + inline T parse(const std::string& hex, const std::string& title) + { + T obj; + Buffer buf((unsigned char *)&obj, sizeof(obj), false); + try { + parse_hex(buf, hex); + } + catch (const BufferException& e) + { + OPENVPN_THROW(buf_hex, title << ": buffer issue: " << e.what()); + } + if (buf.size() != sizeof(obj)) + OPENVPN_THROW(buf_hex, title << ": unexpected size"); + return obj; + } + + } +} + +#endif diff --git a/openvpn/buffer/buflimit.hpp b/openvpn/buffer/buflimit.hpp new file mode 100644 index 0000000..51dce84 --- /dev/null +++ b/openvpn/buffer/buflimit.hpp @@ -0,0 +1,92 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_BUFFER_BUFLIMIT_H +#define OPENVPN_BUFFER_BUFLIMIT_H + +#include + +namespace openvpn { + + template + class BufferLimit + { + public: + BufferLimit() + { + set_max(0, 0); + reset(); + } + + BufferLimit(const T max_lines_arg, + const T max_bytes_arg) + { + set_max(max_lines_arg, max_bytes_arg); + reset(); + } + + void set_max(const T max_lines_arg, + const T max_bytes_arg) + { + max_lines = max_lines_arg; + max_bytes = max_bytes_arg; + } + + void reset() + { + n_bytes = n_lines = 0; + } + + void add(const Buffer& buf) + { + T size = (T)buf.size(); + n_bytes += size; + if (max_bytes && n_bytes > max_bytes) + bytes_exceeded(); + if (max_lines) + { + const unsigned char *p = buf.c_data(); + while (size--) + { + const unsigned char c = *p++; + if (c == '\n') + { + ++n_lines; + if (n_lines > max_lines) + lines_exceeded(); + } + } + } + } + + virtual void bytes_exceeded() = 0; + virtual void lines_exceeded() = 0; + + protected: + T max_lines; + T max_bytes; + T n_bytes; + T n_lines; + }; + +} + +#endif diff --git a/openvpn/buffer/buflineiter.hpp b/openvpn/buffer/buflineiter.hpp new file mode 100644 index 0000000..5fa6d13 --- /dev/null +++ b/openvpn/buffer/buflineiter.hpp @@ -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-2019 OpenVPN Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#pragma once + +#include + +namespace openvpn { + + // Iterate over the lines in a buffer by returning + // a sub-buffer for each line. Zero-copy. + class BufferLineIterator + { + public: + BufferLineIterator(const ConstBuffer& buf) + : src(buf) + { + } + + // Returns a zero-length buffer at end of iteration + ConstBuffer next() + { + return src.read_alloc_buf(line_len()); + } + + private: + size_t line_len() const + { + const unsigned char *const data = src.c_data(); + size_t i = 0; + while (i < src.size()) + if (data[i++] == '\n') + break; + return i; + } + + ConstBuffer src; + }; + +} diff --git a/openvpn/buffer/buflist.hpp b/openvpn/buffer/buflist.hpp new file mode 100644 index 0000000..6a1fe07 --- /dev/null +++ b/openvpn/buffer/buflist.hpp @@ -0,0 +1,122 @@ +// 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 Inc. +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero 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 Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program in the COPYING file. +// If not, see . + +#ifndef OPENVPN_BUFFER_BUFLIST_H +#define OPENVPN_BUFFER_BUFLIST_H + +#include +#include + +#include +#include + +namespace openvpn { + + template